Simple Terminal from SuckLess
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

298 lines
4.9 KiB

16 years ago
16 years ago
  1. /* See LICENSE file for copyright and license details. */
  2. #include <sys/ioctl.h>
  3. #include <sys/select.h>
  4. #include <sys/stat.h>
  5. #include <sys/types.h>
  6. #include <sys/wait.h>
  7. #include <ctype.h>
  8. #include <errno.h>
  9. #include <fcntl.h>
  10. #include <signal.h>
  11. #include <stdarg.h>
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <unistd.h>
  16. #define LENGTH(x) (sizeof(x) / sizeof((x)[0]))
  17. #define MAX(a,b) (((a) > (b)) ? (a) : (b))
  18. #define MIN(a,b) (((a) < (b)) ? (a) : (b))
  19. void buffer(char c);
  20. void cmd(const char *cmdstr, ...);
  21. void *emallocz(unsigned int size);
  22. void eprint(const char *errstr, ...);
  23. void eprintn(const char *errstr, ...);
  24. void getpty(void);
  25. void movea(int x, int y);
  26. void mover(int x, int y);
  27. void parseesc(void);
  28. void scroll(int l);
  29. void shell(void);
  30. void sigchld(int n);
  31. char unbuffer(void);
  32. typedef struct {
  33. unsigned char data[BUFSIZ];
  34. int s, e;
  35. int n;
  36. } RingBuffer;
  37. int cols = 80, lines = 25;
  38. int cx = 0, cy = 0;
  39. int c;
  40. FILE *fptm = NULL;
  41. int ptm, pts;
  42. _Bool bold, digit, qmark;
  43. pid_t pid;
  44. RingBuffer buf;
  45. void
  46. buffer(char c) {
  47. if(buf.n < LENGTH(buf.data))
  48. buf.n++;
  49. else
  50. buf.s = (buf.s + 1) % LENGTH(buf.data);
  51. buf.data[buf.e++] = c;
  52. buf.e %= LENGTH(buf.data);
  53. }
  54. void
  55. cmd(const char *cmdstr, ...) {
  56. va_list ap;
  57. putchar('\n');
  58. putchar(':');
  59. va_start(ap, cmdstr);
  60. vfprintf(stdout, cmdstr, ap);
  61. va_end(ap);
  62. }
  63. void *
  64. emallocz(unsigned int size) {
  65. void *res = calloc(1, size);
  66. if(!res)
  67. eprint("fatal: could not malloc() %u bytes\n", size);
  68. return res;
  69. }
  70. void
  71. eprint(const char *errstr, ...) {
  72. va_list ap;
  73. va_start(ap, errstr);
  74. vfprintf(stderr, errstr, ap);
  75. va_end(ap);
  76. exit(EXIT_FAILURE);
  77. }
  78. void
  79. eprintn(const char *errstr, ...) {
  80. va_list ap;
  81. va_start(ap, errstr);
  82. vfprintf(stderr, errstr, ap);
  83. va_end(ap);
  84. fprintf(stderr, ": %s\n", strerror(errno));
  85. exit(EXIT_FAILURE);
  86. }
  87. void
  88. movea(int x, int y) {
  89. x = MAX(x, cols);
  90. y = MAX(y, lines);
  91. cx = x;
  92. cy = y;
  93. cmd("s %d,%d", x, y);
  94. }
  95. void
  96. mover(int x, int y) {
  97. movea(cx + x, cy + y);
  98. }
  99. void
  100. parseesc(void) {
  101. int i, j;
  102. int arg[16];
  103. memset(arg, 0, LENGTH(arg));
  104. c = getc(fptm);
  105. switch(c) {
  106. case '[':
  107. c = getc(fptm);
  108. for(j = 0; j < LENGTH(arg);) {
  109. if(isdigit(c)) {
  110. digit = 1;
  111. arg[j] *= 10;
  112. arg[j] += c - '0';
  113. }
  114. else if(c == '?')
  115. qmark = 1;
  116. else if(c == ';') {
  117. if(!digit)
  118. eprint("syntax error\n");
  119. digit = 0;
  120. j++;
  121. }
  122. else {
  123. if(digit) {
  124. digit = 0;
  125. j++;
  126. }
  127. break;
  128. }
  129. c = getc(fptm);
  130. }
  131. switch(c) {
  132. case '@':
  133. break;
  134. case 'A':
  135. mover(0, j ? arg[0] : 1);
  136. break;
  137. case 'B':
  138. mover(0, j ? -arg[0] : -1);
  139. break;
  140. case 'C':
  141. mover(j ? arg[0] : 1, 0);
  142. break;
  143. case 'D':
  144. mover(j ? -arg[0] : -1, 0);
  145. break;
  146. case 'E':
  147. /* movel(j ? arg[0] : 1); */
  148. break;
  149. case 'F':
  150. /* movel(j ? -arg[0] : -1); */
  151. break;
  152. case '`':
  153. case 'G':
  154. movea(j ? arg[0] : 1, cy);
  155. break;
  156. case 'f':
  157. case 'H':
  158. movea(arg[1] ? arg[1] : 1, arg[0] ? arg[0] : 1);
  159. case 'L':
  160. /* insline(j ? arg[0] : 1); */
  161. break;
  162. case 'M':
  163. /* delline(j ? arg[0] : 1); */
  164. break;
  165. case 'P':
  166. break;
  167. case 'S':
  168. scroll(j ? arg[0] : 1);
  169. break;
  170. case 'T':
  171. scroll(j ? -arg[0] : -1);
  172. break;
  173. case 'd':
  174. movea(cx, j ? arg[0] : 1);
  175. break;
  176. case 'm':
  177. for(i = 0; i < j; i++) {
  178. if(arg[i] >= 30 && arg[i] <= 37)
  179. cmd("#%d", arg[i] - 30);
  180. if(arg[i] >= 40 && arg[i] <= 47)
  181. cmd("|%d", arg[i] - 40);
  182. /* xterm bright colors */
  183. if(arg[i] >= 90 && arg[i] <= 97)
  184. cmd("#%d", arg[i] - 90);
  185. if(arg[i] >= 100 && arg[i] <= 107)
  186. cmd("|%d", arg[i] - 100);
  187. switch(arg[i]) {
  188. case 0:
  189. case 22:
  190. if(bold)
  191. cmd("b");
  192. case 1:
  193. if(!bold)
  194. cmd("b");
  195. break;
  196. }
  197. }
  198. break;
  199. }
  200. break;
  201. default:
  202. putchar('\033');
  203. ungetc(c, fptm);
  204. }
  205. }
  206. void
  207. scroll(int l) {
  208. cmd("s %d, %d", cx, cy + l);
  209. }
  210. void
  211. shell(void) {
  212. static char *shell = NULL;
  213. if(!shell && !(shell = getenv("SHELL")))
  214. shell = "/bin/sh";
  215. pid = fork();
  216. switch(pid) {
  217. case -1:
  218. eprint("error, cannot fork\n");
  219. case 0:
  220. setsid();
  221. dup2(pts, STDIN_FILENO);
  222. dup2(pts, STDOUT_FILENO);
  223. dup2(pts, STDERR_FILENO);
  224. close(ptm);
  225. putenv("TERM=vt102");
  226. execvp(shell, NULL);
  227. break;
  228. default:
  229. close(pts);
  230. signal(SIGCHLD, sigchld);
  231. }
  232. }
  233. void
  234. sigchld(int n) {
  235. int ret;
  236. if(waitpid(pid, &ret, 0) == -1)
  237. eprintn("error, waiting for child failed");
  238. if(WIFEXITED(ret))
  239. exit(WEXITSTATUS(ret));
  240. else
  241. exit(EXIT_SUCCESS);
  242. }
  243. char
  244. unbuffer(void) {
  245. char c;
  246. c = buf.data[buf.s++];
  247. buf.s %= LENGTH(buf.data);
  248. buf.n--;
  249. return c;
  250. }
  251. int
  252. main(int argc, char *argv[]) {
  253. if(argc == 2 && !strcmp("-v", argv[1]))
  254. eprint("std-"VERSION", © 2008 Matthias-Christian Ott\n");
  255. else if(argc == 1)
  256. eprint("usage: st [-v]\n");
  257. getpty();
  258. shell();
  259. fptm = fdopen(ptm, "r+");
  260. if(!fptm)
  261. eprintn("cannot open slave pty");
  262. for(;;) {
  263. c = getc(fptm);
  264. switch(c) {
  265. case '\033':
  266. parseesc();
  267. break;
  268. default:
  269. putchar(c);
  270. }
  271. }
  272. return 0;
  273. }