diff options
| -rw-r--r-- | std.c | 342 |
1 files changed, 339 insertions, 3 deletions
| @@ -1,4 +1,340 @@ | |||
| 1 | /* See LICENSE file for copyright and license details. */ | 1 | #include <sys/ioctl.h> |
| 2 | #include <sys/select.h> | ||
| 3 | #include <sys/stat.h> | ||
| 4 | #include <sys/types.h> | ||
| 5 | #include <sys/wait.h> | ||
| 6 | #include <ctype.h> | ||
| 7 | #include <errno.h> | ||
| 8 | #include <fcntl.h> | ||
| 9 | #include <signal.h> | ||
| 10 | #include <stdarg.h> | ||
| 11 | #include <stdio.h> | ||
| 12 | #include <stdlib.h> | ||
| 13 | #include <string.h> | ||
| 14 | #include <unistd.h> | ||
| 2 | 15 | ||
| 3 | /* TODO: add the necessary code into here, which is going to be fork()ed from | 16 | #define LENGTH(x) (sizeof (x) / sizeof (x)[0]) |
| 4 | * st if this isn't an attach process */ | 17 | #define MAX(a,b) (((a) > (b)) ? (a) : (b)) |
| 18 | #define MIN(a,b) (((a) < (b)) ? (a) : (b)) | ||
| 19 | |||
| 20 | void buffer(char c); | ||
| 21 | void cmd(const char *cmdstr, ...); | ||
| 22 | void *emallocz(unsigned int size); | ||
| 23 | void eprint(const char *errstr, ...); | ||
| 24 | void eprintn(const char *errstr, ...); | ||
| 25 | void getpty(void); | ||
| 26 | void movea(int x, int y); | ||
| 27 | void mover(int x, int y); | ||
| 28 | void parse(void); | ||
| 29 | void scroll(int l); | ||
| 30 | void shell(void); | ||
| 31 | void sigchld(int n); | ||
| 32 | char unbuffer(void); | ||
| 33 | |||
| 34 | enum { QuestionMark = 1, Digit = 2 }; | ||
| 35 | |||
| 36 | typedef struct { | ||
| 37 | unsigned char data[BUFSIZ]; | ||
| 38 | int s, e; | ||
| 39 | int n; | ||
| 40 | } RingBuffer; | ||
| 41 | |||
| 42 | int cols = 80, lines = 25; | ||
| 43 | int cx = 0, cy = 0; | ||
| 44 | int c, s; | ||
| 45 | FILE *fptm = NULL; | ||
| 46 | int ptm, pts; | ||
| 47 | _Bool bold; | ||
| 48 | pid_t pid; | ||
| 49 | RingBuffer buf; | ||
| 50 | |||
| 51 | void | ||
| 52 | buffer(char c) { | ||
| 53 | if(buf.n < LENGTH(buf.data)) | ||
| 54 | buf.n++; | ||
| 55 | else | ||
| 56 | buf.s = (buf.s + 1) % LENGTH(buf.data); | ||
| 57 | buf.data[buf.e++] = c; | ||
| 58 | buf.e %= LENGTH(buf.data); | ||
| 59 | } | ||
| 60 | |||
| 61 | void | ||
| 62 | cmd(const char *cmdstr, ...) { | ||
| 63 | va_list ap; | ||
| 64 | |||
| 65 | putchar('\n'); | ||
| 66 | putchar(':'); | ||
| 67 | va_start(ap, cmdstr); | ||
| 68 | vfprintf(stdout, cmdstr, ap); | ||
| 69 | va_end(ap); | ||
| 70 | } | ||
| 71 | |||
| 72 | void * | ||
| 73 | emallocz(unsigned int size) { | ||
| 74 | void *res = calloc(1, size); | ||
| 75 | |||
| 76 | if(!res) | ||
| 77 | eprint("fatal: could not malloc() %u bytes\n", size); | ||
| 78 | return res; | ||
| 79 | } | ||
| 80 | |||
| 81 | void | ||
| 82 | eprint(const char *errstr, ...) { | ||
| 83 | va_list ap; | ||
| 84 | |||
| 85 | va_start(ap, errstr); | ||
| 86 | vfprintf(stderr, errstr, ap); | ||
| 87 | va_end(ap); | ||
| 88 | exit(EXIT_FAILURE); | ||
| 89 | } | ||
| 90 | |||
| 91 | void | ||
| 92 | eprintn(const char *errstr, ...) { | ||
| 93 | va_list ap; | ||
| 94 | |||
| 95 | va_start(ap, errstr); | ||
| 96 | vfprintf(stderr, errstr, ap); | ||
| 97 | va_end(ap); | ||
| 98 | fprintf(stderr, ": %s\n", strerror(errno)); | ||
| 99 | exit(EXIT_FAILURE); | ||
| 100 | } | ||
| 101 | |||
| 102 | void | ||
| 103 | getpty(void) { | ||
| 104 | char *ptsdev; | ||
| 105 | |||
| 106 | #if defined(_GNU_SOURCE) | ||
| 107 | ptm = getpt(); | ||
| 108 | #elif _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600 | ||
| 109 | ptm = posix_openpt(O_RDWR); | ||
| 110 | #elif defined(__sgi) | ||
| 111 | ttydev = _getpty(&ptm, O_RDWR, 0622, 0); | ||
| 112 | #elif defined(_AIX) | ||
| 113 | ptm = open("/dev/ptc", O_RDWR); | ||
| 114 | #else | ||
| 115 | ptm = open("/dev/ptmx", O_RDWR); | ||
| 116 | #if defined(__hpux) | ||
| 117 | if(ptm == -1) | ||
| 118 | ptm = open("/dev/ptym/clone", O_RDWR); | ||
| 119 | #endif | ||
| 120 | if(ptm == -1) { | ||
| 121 | if(openpty(&ptm, &pts, NULL, NULL, NULL) == -1) | ||
| 122 | eprintn("error, cannot open pty"); | ||
| 123 | return; | ||
| 124 | } | ||
| 125 | #endif | ||
| 126 | if(ptm != -1) { | ||
| 127 | #if defined(_XOPEN_SOURCE) || !defined(__sgi) || !defined(_AIX) | ||
| 128 | if(grantpt(ptm) == -1) | ||
| 129 | eprintn("error, cannot grant access to pty"); | ||
| 130 | if(unlockpt(ptm) == -1) | ||
| 131 | eprintn("error, cannot unlock pty"); | ||
| 132 | ptsdev = ptsname(ptm); | ||
| 133 | #elif defined(_AIX) | ||
| 134 | ptsdev = ttyname(ptm); | ||
| 135 | #endif | ||
| 136 | if(!ptsdev) | ||
| 137 | eprintn("error, slave pty name undefined"); | ||
| 138 | pts = open(ptsdev, O_RDWR); | ||
| 139 | if(pts == -1) | ||
| 140 | eprintn("error, cannot open slave pty"); | ||
| 141 | puts(ptsdev); | ||
| 142 | #if defined(__hpux) || defined(sun) || defined(__sun) | ||
| 143 | ioctl(pts, I_PUSH, "ptem"); | ||
| 144 | ioctl(pts, I_PUSH, "ldterm"); | ||
| 145 | #endif | ||
| 146 | } | ||
| 147 | else | ||
| 148 | eprintn("error, cannot open pty"); | ||
| 149 | } | ||
| 150 | |||
| 151 | void | ||
| 152 | movea(int x, int y) { | ||
| 153 | x = MAX(x, cols); | ||
| 154 | y = MAX(y, lines); | ||
| 155 | cx = x; | ||
| 156 | cy = y; | ||
| 157 | cmd("s %d,%d", x, y); | ||
| 158 | } | ||
| 159 | |||
| 160 | void | ||
| 161 | mover(int x, int y) { | ||
| 162 | movea(cx + x, cy + y); | ||
| 163 | } | ||
| 164 | |||
| 165 | void | ||
| 166 | parseesc(void) { | ||
| 167 | int i, j; | ||
| 168 | int arg[16]; | ||
| 169 | |||
| 170 | memset(arg, 0, LENGTH(arg)); | ||
| 171 | s = 0; | ||
| 172 | c = getc(fptm); | ||
| 173 | switch(c) { | ||
| 174 | case '[': | ||
| 175 | c = getc(fptm); | ||
| 176 | for(j = 0; j < LENGTH(arg);) { | ||
| 177 | if(isdigit(c)) { | ||
| 178 | s |= Digit; | ||
| 179 | arg[j] *= 10; | ||
| 180 | arg[j] += c - '0'; | ||
| 181 | } | ||
| 182 | else if(c == '?') | ||
| 183 | s |= QuestionMark; | ||
| 184 | else if(c == ';') { | ||
| 185 | if(!(s & Digit)) | ||
| 186 | eprint("syntax error"); | ||
| 187 | s &= ~Digit; | ||
| 188 | j++; | ||
| 189 | } | ||
| 190 | else { | ||
| 191 | if(s & Digit) { | ||
| 192 | s &= ~Digit; | ||
| 193 | j++; | ||
| 194 | } | ||
| 195 | break; | ||
| 196 | } | ||
| 197 | c = getc(fptm); | ||
| 198 | } | ||
| 199 | switch(c) { | ||
| 200 | case '@': | ||
| 201 | break; | ||
| 202 | case 'A': | ||
| 203 | mover(0, j ? arg[0] : 1); | ||
| 204 | break; | ||
| 205 | case 'B': | ||
| 206 | mover(0, j ? -arg[0] : -1); | ||
| 207 | break; | ||
| 208 | case 'C': | ||
| 209 | mover(j ? arg[0] : 1, 0); | ||
| 210 | break; | ||
| 211 | case 'D': | ||
| 212 | mover(j ? -arg[0] : -1, 0); | ||
| 213 | break; | ||
| 214 | case 'E': | ||
| 215 | /* movel(j ? arg[0] : 1); */ | ||
| 216 | break; | ||
| 217 | case 'F': | ||
| 218 | /* movel(j ? -arg[0] : -1); */ | ||
| 219 | break; | ||
| 220 | case '`': | ||
| 221 | case 'G': | ||
| 222 | movea(j ? arg[0] : 1, cy); | ||
| 223 | break; | ||
| 224 | case 'f': | ||
| 225 | case 'H': | ||
| 226 | movea(arg[1] ? arg[1] : 1, arg[0] ? arg[0] : 1); | ||
| 227 | case 'L': | ||
| 228 | /* insline(j ? arg[0] : 1); */ | ||
| 229 | break; | ||
| 230 | case 'M': | ||
| 231 | /* delline(j ? arg[0] : 1); */ | ||
| 232 | break; | ||
| 233 | case 'P': | ||
| 234 | break; | ||
| 235 | case 'S': | ||
| 236 | scroll(j ? arg[0] : 1); | ||
| 237 | break; | ||
| 238 | case 'T': | ||
| 239 | scroll(j ? -arg[0] : -1); | ||
| 240 | break; | ||
| 241 | case 'd': | ||
| 242 | movea(cx, j ? arg[0] : 1); | ||
| 243 | break; | ||
| 244 | case 'm': | ||
| 245 | for(i = 0; i < j; i++) { | ||
| 246 | if(arg[i] >= 30 && arg[i] <= 37) | ||
| 247 | cmd("#%d", arg[i] - 30); | ||
| 248 | if(arg[i] >= 40 && arg[i] <= 47) | ||
| 249 | cmd("|%d", arg[i] - 40); | ||
| 250 | /* xterm bright colors */ | ||
| 251 | if(arg[i] >= 90 && arg[i] <= 97) | ||
| 252 | cmd("#%d", arg[i] - 90); | ||
| 253 | if(arg[i] >= 100 && arg[i] <= 107) | ||
| 254 | cmd("|%d", arg[i] - 100); | ||
| 255 | switch(arg[i]) { | ||
| 256 | case 0: | ||
| 257 | case 22: | ||
| 258 | if(bold) | ||
| 259 | cmd("b"); | ||
| 260 | case 1: | ||
| 261 | if(!bold) | ||
| 262 | cmd("b"); | ||
| 263 | break; | ||
| 264 | } | ||
| 265 | } | ||
| 266 | break; | ||
| 267 | } | ||
| 268 | break; | ||
| 269 | default: | ||
| 270 | putchar('\033'); | ||
| 271 | ungetc(c, fptm); | ||
| 272 | } | ||
| 273 | } | ||
| 274 | |||
| 275 | void | ||
| 276 | scroll(int l) { | ||
| 277 | cmd("s %d, %d", cx, cy + l); | ||
| 278 | } | ||
| 279 | |||
| 280 | void | ||
| 281 | shell(void) { | ||
| 282 | static char *shell = NULL; | ||
| 283 | |||
| 284 | if(!shell && !(shell = getenv("SHELL"))) | ||
| 285 | shell = "/bin/sh"; | ||
| 286 | pid = fork(); | ||
| 287 | switch(pid) { | ||
| 288 | case -1: | ||
| 289 | eprint("error, cannot fork\n"); | ||
| 290 | case 0: | ||
| 291 | setsid(); | ||
| 292 | dup2(pts, STDIN_FILENO); | ||
| 293 | dup2(pts, STDOUT_FILENO); | ||
| 294 | dup2(pts, STDERR_FILENO); | ||
| 295 | close(ptm); | ||
| 296 | putenv("TERM=vt102"); | ||
| 297 | execvp(shell, NULL); | ||
| 298 | break; | ||
| 299 | default: | ||
| 300 | close(pts); | ||
| 301 | signal(SIGCHLD, sigchld); | ||
| 302 | } | ||
| 303 | } | ||
| 304 | |||
| 305 | void | ||
| 306 | sigchld(int n) { | ||
| 307 | int ret; | ||
| 308 | |||
| 309 | if(waitpid(pid, &ret, 0) == -1) | ||
| 310 | eprintn("error, waiting for child failed"); | ||
| 311 | if(WIFEXITED(ret)) | ||
| 312 | exit(WEXITSTATUS(ret)); | ||
| 313 | else | ||
| 314 | exit(EXIT_SUCCESS); | ||
| 315 | } | ||
| 316 | |||
| 317 | char | ||
| 318 | unbuffer(void) { | ||
| 319 | char c; | ||
| 320 | |||
| 321 | c = buf.data[buf.s++]; | ||
| 322 | buf.s %= LENGTH(buf.data); | ||
| 323 | buf.n--; | ||
| 324 | return c; | ||
| 325 | } | ||
| 326 | |||
| 327 | int | ||
| 328 | main(int argc, char *argv[]) { | ||
| 329 | fd_set rd; | ||
| 330 | if(argc == 2 && !strcmp("-v", argv[1])) | ||
| 331 | eprint("std-"VERSION", © 2008 Matthias-Christian Ott\n"); | ||
| 332 | else if(argc == 1) | ||
| 333 | eprint("usage: st [-v]\n"); | ||
| 334 | getpty(); | ||
| 335 | shell(); | ||
| 336 | fdopen(fptm, "r+"); | ||
| 337 | if(!fptm) | ||
| 338 | eprintn("cannot open slave pty"); | ||
| 339 | return 0; | ||
| 340 | } | ||
