| @ -1,4 +1,340 @@ | |||
| /* See LICENSE file for copyright and license details. */ | |||
| #include <sys/ioctl.h> | |||
| #include <sys/select.h> | |||
| #include <sys/stat.h> | |||
| #include <sys/types.h> | |||
| #include <sys/wait.h> | |||
| #include <ctype.h> | |||
| #include <errno.h> | |||
| #include <fcntl.h> | |||
| #include <signal.h> | |||
| #include <stdarg.h> | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #include <unistd.h> | |||
| /* TODO: add the necessary code into here, which is going to be fork()ed from | |||
| * st if this isn't an attach process */ | |||
| #define LENGTH(x) (sizeof (x) / sizeof (x)[0]) | |||
| #define MAX(a,b) (((a) > (b)) ? (a) : (b)) | |||
| #define MIN(a,b) (((a) < (b)) ? (a) : (b)) | |||
| void buffer(char c); | |||
| void cmd(const char *cmdstr, ...); | |||
| void *emallocz(unsigned int size); | |||
| void eprint(const char *errstr, ...); | |||
| void eprintn(const char *errstr, ...); | |||
| void getpty(void); | |||
| void movea(int x, int y); | |||
| void mover(int x, int y); | |||
| void parse(void); | |||
| void scroll(int l); | |||
| void shell(void); | |||
| void sigchld(int n); | |||
| char unbuffer(void); | |||
| enum { QuestionMark = 1, Digit = 2 }; | |||
| typedef struct { | |||
| unsigned char data[BUFSIZ]; | |||
| int s, e; | |||
| int n; | |||
| } RingBuffer; | |||
| int cols = 80, lines = 25; | |||
| int cx = 0, cy = 0; | |||
| int c, s; | |||
| FILE *fptm = NULL; | |||
| int ptm, pts; | |||
| _Bool bold; | |||
| pid_t pid; | |||
| RingBuffer buf; | |||
| void | |||
| buffer(char c) { | |||
| if(buf.n < LENGTH(buf.data)) | |||
| buf.n++; | |||
| else | |||
| buf.s = (buf.s + 1) % LENGTH(buf.data); | |||
| buf.data[buf.e++] = c; | |||
| buf.e %= LENGTH(buf.data); | |||
| } | |||
| void | |||
| cmd(const char *cmdstr, ...) { | |||
| va_list ap; | |||
| putchar('\n'); | |||
| putchar(':'); | |||
| va_start(ap, cmdstr); | |||
| vfprintf(stdout, cmdstr, ap); | |||
| va_end(ap); | |||
| } | |||
| void * | |||
| emallocz(unsigned int size) { | |||
| void *res = calloc(1, size); | |||
| if(!res) | |||
| eprint("fatal: could not malloc() %u bytes\n", size); | |||
| return res; | |||
| } | |||
| void | |||
| eprint(const char *errstr, ...) { | |||
| va_list ap; | |||
| va_start(ap, errstr); | |||
| vfprintf(stderr, errstr, ap); | |||
| va_end(ap); | |||
| exit(EXIT_FAILURE); | |||
| } | |||
| void | |||
| eprintn(const char *errstr, ...) { | |||
| va_list ap; | |||
| va_start(ap, errstr); | |||
| vfprintf(stderr, errstr, ap); | |||
| va_end(ap); | |||
| fprintf(stderr, ": %s\n", strerror(errno)); | |||
| exit(EXIT_FAILURE); | |||
| } | |||
| void | |||
| getpty(void) { | |||
| char *ptsdev; | |||
| #if defined(_GNU_SOURCE) | |||
| ptm = getpt(); | |||
| #elif _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600 | |||
| ptm = posix_openpt(O_RDWR); | |||
| #elif defined(__sgi) | |||
| ttydev = _getpty(&ptm, O_RDWR, 0622, 0); | |||
| #elif defined(_AIX) | |||
| ptm = open("/dev/ptc", O_RDWR); | |||
| #else | |||
| ptm = open("/dev/ptmx", O_RDWR); | |||
| #if defined(__hpux) | |||
| if(ptm == -1) | |||
| ptm = open("/dev/ptym/clone", O_RDWR); | |||
| #endif | |||
| if(ptm == -1) { | |||
| if(openpty(&ptm, &pts, NULL, NULL, NULL) == -1) | |||
| eprintn("error, cannot open pty"); | |||
| return; | |||
| } | |||
| #endif | |||
| if(ptm != -1) { | |||
| #if defined(_XOPEN_SOURCE) || !defined(__sgi) || !defined(_AIX) | |||
| if(grantpt(ptm) == -1) | |||
| eprintn("error, cannot grant access to pty"); | |||
| if(unlockpt(ptm) == -1) | |||
| eprintn("error, cannot unlock pty"); | |||
| ptsdev = ptsname(ptm); | |||
| #elif defined(_AIX) | |||
| ptsdev = ttyname(ptm); | |||
| #endif | |||
| if(!ptsdev) | |||
| eprintn("error, slave pty name undefined"); | |||
| pts = open(ptsdev, O_RDWR); | |||
| if(pts == -1) | |||
| eprintn("error, cannot open slave pty"); | |||
| puts(ptsdev); | |||
| #if defined(__hpux) || defined(sun) || defined(__sun) | |||
| ioctl(pts, I_PUSH, "ptem"); | |||
| ioctl(pts, I_PUSH, "ldterm"); | |||
| #endif | |||
| } | |||
| else | |||
| eprintn("error, cannot open pty"); | |||
| } | |||
| void | |||
| movea(int x, int y) { | |||
| x = MAX(x, cols); | |||
| y = MAX(y, lines); | |||
| cx = x; | |||
| cy = y; | |||
| cmd("s %d,%d", x, y); | |||
| } | |||
| void | |||
| mover(int x, int y) { | |||
| movea(cx + x, cy + y); | |||
| } | |||
| void | |||
| parseesc(void) { | |||
| int i, j; | |||
| int arg[16]; | |||
| memset(arg, 0, LENGTH(arg)); | |||
| s = 0; | |||
| c = getc(fptm); | |||
| switch(c) { | |||
| case '[': | |||
| c = getc(fptm); | |||
| for(j = 0; j < LENGTH(arg);) { | |||
| if(isdigit(c)) { | |||
| s |= Digit; | |||
| arg[j] *= 10; | |||
| arg[j] += c - '0'; | |||
| } | |||
| else if(c == '?') | |||
| s |= QuestionMark; | |||
| else if(c == ';') { | |||
| if(!(s & Digit)) | |||
| eprint("syntax error"); | |||
| s &= ~Digit; | |||
| j++; | |||
| } | |||
| else { | |||
| if(s & Digit) { | |||
| s &= ~Digit; | |||
| j++; | |||
| } | |||
| break; | |||
| } | |||
| c = getc(fptm); | |||
| } | |||
| switch(c) { | |||
| case '@': | |||
| break; | |||
| case 'A': | |||
| mover(0, j ? arg[0] : 1); | |||
| break; | |||
| case 'B': | |||
| mover(0, j ? -arg[0] : -1); | |||
| break; | |||
| case 'C': | |||
| mover(j ? arg[0] : 1, 0); | |||
| break; | |||
| case 'D': | |||
| mover(j ? -arg[0] : -1, 0); | |||
| break; | |||
| case 'E': | |||
| /* movel(j ? arg[0] : 1); */ | |||
| break; | |||
| case 'F': | |||
| /* movel(j ? -arg[0] : -1); */ | |||
| break; | |||
| case '`': | |||
| case 'G': | |||
| movea(j ? arg[0] : 1, cy); | |||
| break; | |||
| case 'f': | |||
| case 'H': | |||
| movea(arg[1] ? arg[1] : 1, arg[0] ? arg[0] : 1); | |||
| case 'L': | |||
| /* insline(j ? arg[0] : 1); */ | |||
| break; | |||
| case 'M': | |||
| /* delline(j ? arg[0] : 1); */ | |||
| break; | |||
| case 'P': | |||
| break; | |||
| case 'S': | |||
| scroll(j ? arg[0] : 1); | |||
| break; | |||
| case 'T': | |||
| scroll(j ? -arg[0] : -1); | |||
| break; | |||
| case 'd': | |||
| movea(cx, j ? arg[0] : 1); | |||
| break; | |||
| case 'm': | |||
| for(i = 0; i < j; i++) { | |||
| if(arg[i] >= 30 && arg[i] <= 37) | |||
| cmd("#%d", arg[i] - 30); | |||
| if(arg[i] >= 40 && arg[i] <= 47) | |||
| cmd("|%d", arg[i] - 40); | |||
| /* xterm bright colors */ | |||
| if(arg[i] >= 90 && arg[i] <= 97) | |||
| cmd("#%d", arg[i] - 90); | |||
| if(arg[i] >= 100 && arg[i] <= 107) | |||
| cmd("|%d", arg[i] - 100); | |||
| switch(arg[i]) { | |||
| case 0: | |||
| case 22: | |||
| if(bold) | |||
| cmd("b"); | |||
| case 1: | |||
| if(!bold) | |||
| cmd("b"); | |||
| break; | |||
| } | |||
| } | |||
| break; | |||
| } | |||
| break; | |||
| default: | |||
| putchar('\033'); | |||
| ungetc(c, fptm); | |||
| } | |||
| } | |||
| void | |||
| scroll(int l) { | |||
| cmd("s %d, %d", cx, cy + l); | |||
| } | |||
| void | |||
| shell(void) { | |||
| static char *shell = NULL; | |||
| if(!shell && !(shell = getenv("SHELL"))) | |||
| shell = "/bin/sh"; | |||
| pid = fork(); | |||
| switch(pid) { | |||
| case -1: | |||
| eprint("error, cannot fork\n"); | |||
| case 0: | |||
| setsid(); | |||
| dup2(pts, STDIN_FILENO); | |||
| dup2(pts, STDOUT_FILENO); | |||
| dup2(pts, STDERR_FILENO); | |||
| close(ptm); | |||
| putenv("TERM=vt102"); | |||
| execvp(shell, NULL); | |||
| break; | |||
| default: | |||
| close(pts); | |||
| signal(SIGCHLD, sigchld); | |||
| } | |||
| } | |||
| void | |||
| sigchld(int n) { | |||
| int ret; | |||
| if(waitpid(pid, &ret, 0) == -1) | |||
| eprintn("error, waiting for child failed"); | |||
| if(WIFEXITED(ret)) | |||
| exit(WEXITSTATUS(ret)); | |||
| else | |||
| exit(EXIT_SUCCESS); | |||
| } | |||
| char | |||
| unbuffer(void) { | |||
| char c; | |||
| c = buf.data[buf.s++]; | |||
| buf.s %= LENGTH(buf.data); | |||
| buf.n--; | |||
| return c; | |||
| } | |||
| int | |||
| main(int argc, char *argv[]) { | |||
| fd_set rd; | |||
| if(argc == 2 && !strcmp("-v", argv[1])) | |||
| eprint("std-"VERSION", © 2008 Matthias-Christian Ott\n"); | |||
| else if(argc == 1) | |||
| eprint("usage: st [-v]\n"); | |||
| getpty(); | |||
| shell(); | |||
| fdopen(fptm, "r+"); | |||
| if(!fptm) | |||
| eprintn("cannot open slave pty"); | |||
| return 0; | |||
| } | |||