/** * Stores the current cursor column in '*cols'. * Returns 1 if OK, or 0 if failed to determine cursor pos. */ static int queryCursor(int fd, int* cols) { /* control sequence - report cursor location */ fd_printf(fd, "\x1b[6n"); /* Parse the response: ESC [ rows ; cols R */ if (fd_read_char(fd, 100) == 0x1b && fd_read_char(fd, 100) == '[') { int n = 0; while (1) { int ch = fd_read_char(fd, 100); if (ch == ';') { /* Ignore rows */ n = 0; } else if (ch == 'R') { /* Got cols */ if (n != 0 && n < 1000) { *cols = n; } break; } else if (ch >= 0 && ch <= '9') { n = n * 10 + ch - '0'; } else { break; } } return 1; } return 0; }
/** * If escape (27) was received, reads subsequent * chars to determine if this is a known special key. * * Returns SPECIAL_NONE if unrecognised, or -1 if EOF. * * If no additional char is received within a short time, * 27 is returned. */ static int check_special(int fd) { int c = fd_read_char(fd, 50); int c2; if (c < 0) { return 27; } c2 = fd_read_char(fd, 50); if (c2 < 0) { return c2; } if (c == '[' || c == 'O') { /* Potential arrow key */ switch (c2) { case 'A': return SPECIAL_UP; case 'B': return SPECIAL_DOWN; case 'C': return SPECIAL_RIGHT; case 'D': return SPECIAL_LEFT; case 'F': return SPECIAL_END; case 'H': return SPECIAL_HOME; } } if (c == '[' && c2 >= '1' && c2 <= '8') { /* extended escape */ c = fd_read_char(fd, 50); if (c == '~') { switch (c2) { case '2': return SPECIAL_INSERT; case '3': return SPECIAL_DELETE; case '5': return SPECIAL_PAGE_UP; case '6': return SPECIAL_PAGE_DOWN; case '7': return SPECIAL_HOME; case '8': return SPECIAL_END; } } while (c != -1 && c != '~') { /* .e.g \e[12~ or '\e[11;2~ discard the complete sequence */ c = fd_read_char(fd, 50); } } return SPECIAL_NONE; }
static int getWindowSize(struct current *current) { struct winsize ws; if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0 && ws.ws_col != 0) { current->cols = ws.ws_col; return 0; } /* Failed to query the window size. Perhaps we are on a serial terminal. * Try to query the width by sending the cursor as far to the right * and reading back the cursor position. * Note that this is only done once per call to linenoise rather than * every time the line is refreshed for efficiency reasons. */ if (current->cols == 0) { current->cols = 80; /* Move cursor far right and report cursor position, then back to the left */ fd_printf(current->fd, "\x1b[999C" "\x1b[6n"); /* Parse the response: ESC [ rows ; cols R */ if (fd_read_char(current->fd, 100) == 0x1b && fd_read_char(current->fd, 100) == '[') { int n = 0; while (1) { int ch = fd_read_char(current->fd, 100); if (ch == ';') { /* Ignore rows */ n = 0; } else if (ch == 'R') { /* Got cols */ if (n != 0 && n < 1000) { current->cols = n; } break; } else if (ch >= 0 && ch <= '9') { n = n * 10 + ch - '0'; } else { break; } } } } return 0; }
/** * Reads a complete utf-8 character * and returns the unicode value, or -1 on error. */ static int fd_read(struct current *current) { #ifdef USE_UTF8 char buf[4]; int n; int i; int c; if (read(current->fd, &buf[0], 1) != 1) { return -1; } n = utf8_charlen(buf[0]); if (n < 1 || n > 3) { return -1; } for (i = 1; i < n; i++) { if (read(current->fd, &buf[i], 1) != 1) { return -1; } } buf[n] = 0; /* decode and return the character */ utf8_tounicode(buf, &c); return c; #else return fd_read_char(current->fd, -1); #endif }