| @ -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; | |||||
| } | |||||