summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Ankarström <john@ankarstrom.se>2020-11-06 18:42:26 +0100
committerJohn Ankarström <john@ankarstrom.se>2020-11-06 18:42:26 +0100
commite169dbe7c20ed4b4b1acf80c8e03e9aa58a60836 (patch)
tree3f45098e6691dd3530ce278641970f46f90c002e
downloadlst-e169dbe7c20ed4b4b1acf80c8e03e9aa58a60836.tar.gz
add cpr function, basic setup
-rw-r--r--Makefile4
-rw-r--r--l.c137
2 files changed, 141 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..62f142f
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,4 @@
+all: l
+
+%: %c
+ gcc -o $@ $<
diff --git a/l.c b/l.c
new file mode 100644
index 0000000..2248da6
--- /dev/null
+++ b/l.c
@@ -0,0 +1,137 @@
+#include <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <sys/ttydefaults.h>
+#include <termios.h>
+#include <unistd.h>
+
+#define ESC "\033"
+#define CSI ESC "["
+
+int ttyfd;
+
+/* enable/disable "raw" mode */
+void raw(bool enable) {
+ int r;
+ static struct termios orig;
+ struct termios raw;
+
+ if (enable) {
+ r = tcgetattr(0, &orig);
+ if (r == -1) err(1, "tcgetattr");
+
+ raw = orig;
+ raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
+ raw.c_oflag &= ~OPOST;
+ raw.c_cflag |= CS8;
+ raw.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
+
+ r = tcsetattr(0, TCSAFLUSH, &raw);
+ if (r == -1) err(1, "tcsetattr");
+
+ } else
+ tcsetattr(0, TCSAFLUSH, &orig);
+}
+
+/* cursor position report */
+int cpr(int *x, int *y) {
+ char c, xbuf[4], ybuf[4];
+ int i;
+
+ write (1, CSI "6n", 2+2);
+
+ /* get CSI */
+ read(1, &c, 1);
+ if (c != '\033') return -1;
+ read(1, &c, 1);
+ if (c != '[') return -1;
+
+ /* get x */
+ i = 0;
+ while (read(1, &c, 1) && c != ';') {
+ if (i > 3 || !isdigit(c)) return -1;
+ ybuf[i++] = c;
+ }
+ if (i == 0) return -1;
+ ybuf[i] = '\0';
+
+ /* get y */
+ i = 0;
+ while (read(1, &c, 1) && c != 'R') {
+ if (i > 3 || !isdigit(c)) return -1;
+ xbuf[i++] = c;
+ }
+ if (i == 0) return -1;
+ xbuf[i] = '\0';
+
+ *x = atoi(xbuf);
+ *y = atoi(ybuf);
+
+ return 0;
+}
+
+void up() {}
+void down() {}
+void right() {}
+void left() {}
+
+int main() {
+ char c, *p;
+ char *ex = "file1 file2 file3\r\nfile4 file5 file6\r\nfile7";
+ int i, r, x, x2, y, y2;
+ struct winsize w;
+
+ ttyfd = open("/dev/tty", O_RDWR);
+ if (ttyfd == -1) err(1, "open");
+
+ raw(true);
+
+ /* save original cursor position */
+ r = cpr(&x, &y);
+ if (r == -1) goto quit;
+
+ /* print output */
+ dprintf(ttyfd, "%s", ex);
+
+ /* get height of output */
+ p = ex - 1;
+ i = 0;
+ while (*(++p) != '\0')
+ if (*p == '\n') i++;
+
+ /* get height of terminal */
+ r = ioctl(ttyfd, TIOCGWINSZ, &w);
+ if (r == -1) err(1, "ioctl");
+
+ /* correct cursor position if original cursor was near bottom */
+ r = y + i - w.ws_row;
+ if (r > 0)
+ y = y - r;
+
+ /* restore original cursor position */
+ dprintf(ttyfd, "%s%d;%dH", CSI, y, x); /* restore cursor position (CUP) */
+
+ while (read(0, &c, 1) != 0) {
+ switch (c) {
+ case 'q':
+ goto quit;
+ break;
+ case '\033':
+ read(0, &c, 1);
+ if (c != '[') break;
+ read(0, &c, 1);
+ if (c == 'A') up();
+ if (c == 'B') down();
+ if (c == 'C') right();
+ if (c == 'D') left();
+ break;
+ }
+ }
+
+quit:
+ raw(false);
+}