1 /*
2
3 Minimum Profit - A Text Editor
4 Raw ANSI terminal driver.
5
6 ttcdt <dev@triptico.com> et al.
7
8 This software is released into the public domain.
9 NO WARRANTY. See file LICENSE for details.
10
11 */
12
13 #include "config.h"
14
15 #ifdef CONFOPT_ANSI
16
17 #include <stdio.h>
18 #include <termios.h>
19 #include <unistd.h>
20 #include <sys/select.h>
21 #include <signal.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <wchar.h>
25 #include <sys/time.h>
26
27 #include "mpdm.h"
28 #include "mpsl.h"
29 #include "mp.h"
30
31
32 #define MAX_COLORS 100
33 char ansi_attrs[MAX_COLORS][64];
34 int ansi_attrs_i = 0;
35 int normal_attr = 0;
36
37 static int idle_msecs = 0;
38
39
40 /** code **/
41
ansi_raw_tty(int start)42 static void ansi_raw_tty(int start)
43 /* sets/unsets stdin in raw mode */
44 {
45 static struct termios so;
46
47 if (start) {
48 struct termios o;
49
50 /* save previous fd state */
51 tcgetattr(0, &so);
52
53 /* set raw */
54 tcgetattr(0, &o);
55 cfmakeraw(&o);
56 tcsetattr(0, TCSANOW, &o);
57 }
58 else
59 /* restore previously saved tty state */
60 tcsetattr(0, TCSANOW, &so);
61 }
62
63
ansi_something_waiting(int fd,int msecs)64 static int ansi_something_waiting(int fd, int msecs)
65 /* returns yes if there is something waiting on fd */
66 {
67 fd_set ids;
68 struct timeval tv;
69
70 /* reset */
71 FD_ZERO(&ids);
72
73 /* add fd to set */
74 FD_SET(fd, &ids);
75
76 tv.tv_sec = 0;
77 tv.tv_usec = msecs * 1000;
78
79 return select(1, &ids, NULL, NULL, &tv) > 0;
80 }
81
82
ansi_read_string(int fd)83 char *ansi_read_string(int fd)
84 /* reads an ansi string, waiting in the first char */
85 {
86 static char *buf = NULL;
87 static int z = 0;
88 int n = 0;
89
90 /* if there is an idle time and nothing is here, exit */
91 if (idle_msecs > 0 && !ansi_something_waiting(fd, idle_msecs))
92 return NULL;
93
94 /* first char blocks, rest of possible chars not */
95 do {
96 char c;
97
98 if (read(fd, &c, sizeof(c)) == -1)
99 break;
100 else {
101 if (n == z) {
102 z += 32;
103 buf = realloc(buf, z + 1);
104 }
105
106 buf[n++] = c;
107 }
108
109 } while (ansi_something_waiting(fd, 10));
110
111 buf[n] = '\0';
112
113 return n ? buf : NULL;
114 }
115
116
117 static void ansi_db_resize(int w, int h);
118
ansi_get_tty_size(void)119 static void ansi_get_tty_size(void)
120 /* asks the tty for its size */
121 {
122 mpdm_t v;
123 char *buffer;
124 int w, h;
125
126 /* magic line: save cursor position, move to stupid position,
127 ask for current position and restore cursor position */
128 printf("\0337\033[r\033[999;999H\033[6n\0338");
129 fflush(stdout);
130
131 buffer = ansi_read_string(0);
132
133 sscanf(buffer, "\033[%d;%dR", &h, &w);
134
135 v = mpdm_get_wcs(MP, L"window");
136 mpdm_set_wcs(v, MPDM_I(w), L"tx");
137 mpdm_set_wcs(v, MPDM_I(h - 1), L"ty");
138
139 ansi_db_resize(w, h + 1);
140 }
141
142
ansi_sigwinch(int s)143 static void ansi_sigwinch(int s)
144 /* SIGWINCH signal handler */
145 {
146 struct sigaction sa;
147
148 /* get new size */
149 ansi_get_tty_size();
150
151 /* (re)attach signal */
152 memset(&sa, '\0', sizeof(sa));
153 sa.sa_handler = ansi_sigwinch;
154 sigaction(SIGWINCH, &sa, NULL);
155 }
156
157
ansi_gotoxy(int x,int y)158 static void ansi_gotoxy(int x, int y)
159 /* positions the cursor */
160 {
161 printf("\033[%d;%dH", y + 1, x + 1);
162 }
163
164
165 #if 0
166 static void ansi_getxy(int *x, int *y)
167 /* gets the x and y cursor position */
168 {
169 char *buffer;
170
171 printf("\033[6n");
172 fflush(stdout);
173
174 buffer = ansi_read_string(0);
175 sscanf(buffer, "\033[%d;%dR", y, x);
176
177 (*x)--;
178 (*y)--;
179 }
180
181
182 static void ansi_clreol(void)
183 /* clear to end of line */
184 {
185 printf("\033[K");
186 }
187
188
189 static void ansi_clrscr(void)
190 /* clears the screen */
191 {
192 printf("\033[2J");
193 }
194
195
196 static void ansi_print_v(mpdm_t v)
197 /* prints an mpdm_t */
198 {
199 char tmp[1024];
200
201 wcstombs(tmp, mpdm_string(v), sizeof(tmp));
202 printf("%s", tmp);
203 }
204
205
206 static wchar_t ansi_charat(int x, int y)
207 /* returns the char at the x, y position */
208 {
209 return L' ';
210 }
211 #endif
212
ansi_set_attr(int a)213 static int ansi_set_attr(int a)
214 {
215 printf("%s", ansi_attrs[a]);
216
217 return a;
218 }
219
220
ansi_refresh(void)221 static void ansi_refresh(void)
222 /* refresh the screen */
223 {
224 fflush(stdout);
225 }
226
227
ansi_build_colors(void)228 static void ansi_build_colors(void)
229 {
230 mpdm_t colors;
231 mpdm_t color_names;
232 mpdm_t v, i;
233 int n, c;
234 int rgbcolor = 0;
235
236 v = mpdm_get_wcs(MP, L"config");
237 rgbcolor = mpdm_ival(mpdm_get_wcs(v, L"ansi_rgbcolor"));
238
239 /* gets the color definitions and attribute names */
240 colors = mpdm_get_wcs(MP, L"colors");
241 color_names = mpdm_get_wcs(MP, L"color_names");
242
243 /* loop the colors */
244 n = c = 0;
245 while (mpdm_iterator(colors, &c, &v, &i)) {
246 mpdm_t w;
247 int c0, c1, cf = 0;
248
249 /* store the 'normal' attribute */
250 if (wcscmp(mpdm_string(i), L"normal") == 0)
251 normal_attr = n;
252
253 /* flags */
254 w = mpdm_get_wcs(v, L"flags");
255 if (mpdm_seek_wcs(w, L"reverse", 1) != -1)
256 cf |= 0x01;
257 if (mpdm_seek_wcs(w, L"bright", 1) != -1)
258 cf |= 0x02;
259 if (mpdm_seek_wcs(w, L"underline", 1) != -1)
260 cf |= 0x04;
261
262 if (rgbcolor) {
263 w = mpdm_get_wcs(v, L"gui");
264 c0 = mpdm_ival(mpdm_get_i(w, 0));
265 c1 = mpdm_ival(mpdm_get_i(w, 1));
266
267 sprintf(ansi_attrs[n], "\033[0;%s%s38;2;%d;%d;%dm\033[48;2;%d;%d;%dm",
268 cf & 0x1 ? "7;" : "",
269 cf & 0x4 ? "4;" : "",
270 (c0 >> 16) & 0xff, (c0 >> 8) & 0xff, c0 & 0xff,
271 (c1 >> 16) & 0xff, (c1 >> 8) & 0xff, c1 & 0xff
272 );
273 }
274 else {
275 w = mpdm_get_wcs(v, L"text");
276
277 /* get color indexes */
278 if ((c0 = mpdm_seek(color_names, mpdm_get_i(w, 0), 1)) == -1 ||
279 (c1 = mpdm_seek(color_names, mpdm_get_i(w, 1), 1)) == -1)
280 continue;
281
282 if ((--c0) == -1) c0 = 9;
283 if ((--c1) == -1) c1 = 9;
284
285 sprintf(ansi_attrs[n], "\033[0;%s%s%s%d;%dm",
286 cf & 0x1 ? "7;" : "",
287 cf & 0x2 ? "1;" : "",
288 cf & 0x4 ? "4;" : "",
289 c0 + 30,
290 c1 + 40
291 );
292 }
293
294 /* store the attr */
295 mpdm_set_wcs(v, MPDM_I(n), L"attr");
296
297 n++;
298 }
299
300 ansi_attrs_i = n;
301 }
302
303
304 struct _str_to_code {
305 char *ansi_str;
306 wchar_t *code;
307 } str_to_code[] = {
308 { "\033[A\033[A\033[A", L"mouse-wheel-up" },
309 { "\033[B\033[B\033[B", L"mouse-wheel-down" },
310 { "\033[A", L"cursor-up" },
311 { "\033[B", L"cursor-down" },
312 { "\033[C", L"cursor-right" },
313 { "\033[D", L"cursor-left" },
314 { "\033[5~", L"page-up" },
315 { "\033[6~", L"page-down" },
316 { "\033[H", L"home" },
317 { "\033[F", L"end" },
318 { "\033OP", L"f1" },
319 { "\033OQ", L"f2" },
320 { "\033OR", L"f3" },
321 { "\033OS", L"f4" },
322 { "\033[15~", L"f5" },
323 { "\033[17~", L"f6" },
324 { "\033[18~", L"f7" },
325 { "\033[19~", L"f8" },
326 { "\033[20~", L"f9" },
327 { "\033[21~", L"f10" },
328 { "\033[1;2P", L"shift-f1" },
329 { "\033[1;2Q", L"shift-f2" },
330 { "\033[1;2R", L"shift-f3" },
331 { "\033[1;2S", L"shift-f4" },
332 { "\033[15;2~", L"shift-f5" },
333 { "\033[17;2~", L"shift-f6" },
334 { "\033[18;2~", L"shift-f7" },
335 { "\033[19;2~", L"shift-f8" },
336 { "\033[20;2~", L"shift-f9" },
337 { "\033[21;2~", L"shift-f10" },
338 { "\033[1;5P", L"ctrl-f1" },
339 { "\033[1;5Q", L"ctrl-f2" },
340 { "\033[1;5R", L"ctrl-f3" },
341 { "\033[1;5S", L"ctrl-f4" },
342 { "\033[15;5~", L"ctrl-f5" },
343 { "\033[17;5~", L"ctrl-f6" },
344 { "\033[18;5~", L"ctrl-f7" },
345 { "\033[19;5~", L"ctrl-f8" },
346 { "\033[20;5~", L"ctrl-f9" },
347 { "\033[21;5~", L"ctrl-f10" },
348 { "\033[1;2A", L"_shift-cursor-up" },
349 { "\033[1;2B", L"_shift-cursor-down" },
350 { "\033[1;2C", L"_shift-cursor-right" },
351 { "\033[1;2D", L"_shift-cursor-left" },
352 { "\033[1;5A", L"ctrl-cursor-up" },
353 { "\033[1;5B", L"ctrl-cursor-down" },
354 { "\033[1;5C", L"ctrl-cursor-right" },
355 { "\033[1;5D", L"ctrl-cursor-left" },
356 { "\033[1;5H", L"ctrl-home" },
357 { "\033[1;5F", L"ctrl-end" },
358 { "\033[1;3A", L"alt-cursor-up" },
359 { "\033[1;3B", L"alt-cursor-down" },
360 { "\033[1;3C", L"alt-cursor-right" },
361 { "\033[1;3D", L"alt-cursor-left" },
362 { "\033[1;3H", L"alt-home" },
363 { "\033[1;3F", L"alt-end" },
364 { "\033[3~", L"delete" },
365 { "\033[2~", L"insert" },
366 { "\033[Z", L"shift-tab" },
367 { "\033\r", L"alt-enter" },
368 { "\033[1~", L"home" },
369 { "\033[4~", L"end" },
370 { "\033[5;5~", L"ctrl-page-up" },
371 { "\033[6;5~", L"ctrl-page-down" },
372 { "\033[5;3~", L"alt-page-up" },
373 { "\033[6;3~", L"alt-page-down" },
374 { "\033-", L"alt-minus" },
375 { "\033\033[A", L"alt-cursor-up" },
376 { "\033\033[B", L"alt-cursor-down" },
377 { "\033\033[C", L"alt-cursor-right" },
378 { "\033\033[D", L"alt-cursor-left" },
379 { "\033\033[1~", L"alt-home" },
380 { "\033\033[2~", L"alt-insert" },
381 { "\033\033[3~", L"alt-delete" },
382 { "\033\033[4~", L"alt-end" },
383 { "\033\033[5~", L"alt-page-up" },
384 { "\033\033[6~", L"alt-page-down" },
385 { "\033OA", L"ctrl-cursor-up" },
386 { "\033OB", L"ctrl-cursor-down" },
387 { "\033OD", L"ctrl-cursor-left" },
388 { "\033OC", L"ctrl-cursor-right" },
389 { "\033[11~", L"f1" },
390 { "\033[12~", L"f2" },
391 { "\033[13~", L"f3" },
392 { "\033[14~", L"f4" },
393 { NULL, NULL }
394 };
395
396 #define ctrl(k) ((k) & 31)
397
ansi_getkey(mpdm_t args,mpdm_t ctxt)398 static mpdm_t ansi_getkey(mpdm_t args, mpdm_t ctxt)
399 {
400 char *str;
401 wchar_t *f = NULL;
402 mpdm_t k = NULL;
403
404 str = ansi_read_string(0);
405
406 if (str) {
407 /* only one char? it's an ASCII or ctrl character */
408 if (str[1] == '\0') {
409 if (str[0] == ' ')
410 f = L"space";
411 else
412 if (str[0] == '\r')
413 f = L"enter";
414 else
415 if (str[0] == '\t')
416 f = L"tab";
417 else
418 if (str[0] == '\033')
419 f = L"escape";
420 else
421 if (str[0] == '\b' || str[0] == '\177')
422 f = L"backspace";
423 else
424 if (str[0] >= ctrl('a') && str[0] <= ctrl('z')) {
425 char tmp[32];
426
427 sprintf(tmp, "ctrl-%c", str[0] + 'a' - ctrl('a'));
428 k = MPDM_MBS(tmp);
429 }
430 else
431 if (str[0] == ctrl(' '))
432 f = L"ctrl-space";
433 else
434 k = MPDM_MBS(str);
435 }
436
437 /* esc+letter? alt-letter */
438 if (str[0] == '\033' && str[1] >= 'a' &&
439 str[1] <= 'z' && str[2] == '\0') {
440 char tmp[16];
441
442 sprintf(tmp, "alt-%c", str[1]);
443 k = MPDM_MBS(tmp);
444 }
445
446 /* if it's a string that starts with a backspace,
447 it's probably a sequence of them, so treat it as only one */
448 if (str[0] == '\b' || str[0] == '\177')
449 f = L"backspace";
450
451 /* still nothing? search the table of keys */
452 if (k == NULL && f == NULL) {
453 int n;
454 char *ptr;
455
456 for (n = 0; (ptr = str_to_code[n].ansi_str) != NULL; n++) {
457 if (strncmp(ptr, str, strlen(ptr)) == 0) {
458 f = str_to_code[n].code;
459 break;
460 }
461 }
462
463 /* if a found key starts with _shift-, set shift_pressed flag */
464 if (f && wcsncmp(f, L"_shift-", 7) == 0) {
465 mpdm_set_wcs(MP, MPDM_I(1), L"shift_pressed");
466 f += 7;
467 }
468 }
469
470 /* if there is still no recognized ANSI string, return string as is */
471 if (k == NULL && f == NULL) {
472 int n;
473 mpdm_t v;
474
475 /* convert carriage returns to new lines */
476 for (n = 0; str[n]; n++) {
477 if (str[n] == '\r')
478 str[n] = '\n';
479 }
480
481 v = MPDM_MBS(str);
482
483 if (mpdm_size(v) == 1) {
484 /* return as is */
485 k = v;
486 }
487 else {
488 /* more than one char */
489 mpdm_set_wcs(MP, v, L"raw_string");
490 f = L"insert-raw-string";
491 }
492 }
493
494 /* if something, create a value */
495 if (k == NULL && f != NULL)
496 k = MPDM_S(f);
497 }
498 else
499 k = MPDM_S(L"idle");
500
501 return k;
502 }
503
504
ansi_drv_idle(mpdm_t a,mpdm_t ctxt)505 static mpdm_t ansi_drv_idle(mpdm_t a, mpdm_t ctxt)
506 {
507 idle_msecs = (int) (mpdm_rval(mpdm_get_i(a, 0)) * 1000);
508
509 return NULL;
510 }
511
512
ansi_drv_shutdown(mpdm_t a,mpdm_t ctxt)513 static mpdm_t ansi_drv_shutdown(mpdm_t a, mpdm_t ctxt)
514 {
515 mpdm_t v;
516
517 ansi_raw_tty(0);
518
519 /* set default attribute */
520 printf("\033[0;39;49m\n");
521
522 /* leave alternate screen */
523 printf("\033[?1049l\n");
524
525 if ((v = mpdm_get_wcs(MP, L"exit_message")) != NULL) {
526 mpdm_write_wcs(stdout, mpdm_string(v));
527 printf("\n");
528 }
529
530 return NULL;
531 }
532
533
ansi_drv_suspend(mpdm_t a,mpdm_t ctxt)534 static mpdm_t ansi_drv_suspend(mpdm_t a, mpdm_t ctxt)
535 {
536 ansi_raw_tty(0);
537
538 printf("\nType 'fg' to return to Minimum Profit");
539 fflush(stdout);
540
541 /* Trigger suspending this process */
542 kill(getpid(), SIGSTOP);
543
544 ansi_raw_tty(1);
545
546 return NULL;
547 }
548
549
550 /** double buffer **/
551
552 /* cursor position */
553 static int db_x = 0;
554 static int db_y = 0;
555
556 /* buffer size */
557 static int db_width = 0;
558 static int db_height = 0;
559
560 /* buffers */
561 static unsigned int *db_scr = NULL;
562 static unsigned int *db_scr_o = NULL;
563
564 /* last attr set */
565 static unsigned int db_attr = 0;
566
567
ansi_db_resize(int w,int h)568 static void ansi_db_resize(int w, int h)
569 /* initialize a new double buffer with a new size */
570 {
571 /* alloc new space */
572 free(db_scr);
573 db_scr = (unsigned int *)calloc(w * h, sizeof(unsigned int));
574 free(db_scr_o);
575 db_scr_o = (unsigned int *)calloc(w * h, sizeof(unsigned int));
576
577 db_x = 0;
578 db_y = 0;
579 db_width = w;
580 db_height = h;
581 }
582
583
ansi_db_print_v(mpdm_t v)584 static void ansi_db_print_v(mpdm_t v)
585 /* print a value */
586 {
587 int i = db_y * db_width;
588 wchar_t *p = mpdm_string(v);
589
590 if (db_y < db_height - 1) {
591 /* copy the string to current position */
592 while (db_x < db_width && *p) {
593 db_scr[i + db_x++] = ((unsigned int)*p * ansi_attrs_i) + db_attr;
594 p++;
595 }
596 }
597 }
598
599
ansi_db_gotoxy(int x,int y)600 static void ansi_db_gotoxy(int x, int y)
601 /* set cursor position */
602 {
603 db_x = x;
604 db_y = y;
605 }
606
607
ansi_db_clreol(void)608 static void ansi_db_clreol(void)
609 /* clear to end of line */
610 {
611 int i = db_y * db_width;
612 unsigned int c = ' ' * ansi_attrs_i + db_attr;
613 int n = db_x;
614
615 /* fill the rest of the line with blanks */
616 while (n < db_width)
617 db_scr[i + n++] = c;
618 }
619
620
ansi_db_set_attr(int a)621 static void ansi_db_set_attr(int a)
622 /* set attribute for next characters */
623 {
624 db_attr = a;
625 }
626
627
ansi_db_refresh(void)628 static void ansi_db_refresh(void)
629 /* dump the buffer to the screen */
630 {
631 int n, m;
632 int p_attr = -1;
633
634 p_attr = ansi_set_attr(normal_attr);
635
636 for (n = 0; n < db_height; n++) {
637 int i = n * db_width;
638
639 for (m = 0; m < db_width; m++) {
640 /* different content? */
641 if (db_scr[i + m] != db_scr_o[i + m]) {
642 wchar_t w;
643 int a;
644 char tmp[64];
645
646 ansi_gotoxy(m, n);
647
648 /* unpack character and attr */
649 w = db_scr[i + m] / ansi_attrs_i;
650 a = db_scr[i + m] % ansi_attrs_i;
651
652 /* write attr if different from the already set */
653 if (a != p_attr)
654 p_attr = ansi_set_attr(a);
655
656 tmp[wctomb(tmp, w)] = '\0';
657 printf("%s", tmp);
658 }
659 }
660 }
661
662 ansi_gotoxy(db_x, db_y);
663
664 ansi_refresh();
665
666 /* save buffer */
667 memcpy(db_scr_o, db_scr, db_width * db_height * sizeof(wchar_t));
668 }
669
670
ansi_db_getxy(int * x,int * y)671 static void ansi_db_getxy(int *x, int *y)
672 /* get cursor position */
673 {
674 *x = db_x;
675 *y = db_y;
676 }
677
678
ansi_db_charat(int x,int y)679 static wchar_t ansi_db_charat(int x, int y)
680 /* get character at position */
681 {
682 int i = y * db_width + x;
683
684 return db_scr[i] / ansi_attrs_i;
685 }
686
687
688 /** TUI **/
689
ansi_tui_addstr(mpdm_t a,mpdm_t ctxt)690 static mpdm_t ansi_tui_addstr(mpdm_t a, mpdm_t ctxt)
691 /* TUI: add a string */
692 {
693 ansi_db_print_v(mpdm_get_i(a, 0));
694
695 return NULL;
696 }
697
698
ansi_tui_move(mpdm_t a,mpdm_t ctxt)699 static mpdm_t ansi_tui_move(mpdm_t a, mpdm_t ctxt)
700 /* TUI: move to a screen position */
701 {
702 ansi_db_gotoxy(mpdm_ival(mpdm_get_i(a, 0)), mpdm_ival(mpdm_get_i(a, 1)));
703
704 /* if third argument is not NULL, clear line */
705 if (mpdm_get_i(a, 2) != NULL)
706 ansi_db_clreol();
707
708 return NULL;
709 }
710
711
ansi_tui_attr(mpdm_t a,mpdm_t ctxt)712 static mpdm_t ansi_tui_attr(mpdm_t a, mpdm_t ctxt)
713 /* TUI: set attribute for next string */
714 {
715 ansi_db_set_attr(mpdm_ival(mpdm_get_i(a, 0)));
716
717 return NULL;
718 }
719
720
ansi_tui_refresh(mpdm_t a,mpdm_t ctxt)721 static mpdm_t ansi_tui_refresh(mpdm_t a, mpdm_t ctxt)
722 /* TUI: refresh the screen */
723 {
724 ansi_db_refresh();
725
726 return NULL;
727 }
728
729
ansi_doc_draw(mpdm_t args,mpdm_t ctxt)730 static mpdm_t ansi_doc_draw(mpdm_t args, mpdm_t ctxt)
731 /* draw the document */
732 {
733 mpdm_t d;
734 int n, m;
735
736 d = mpdm_get_i(args, 0);
737 d = mpdm_ref(mp_draw(d, 0));
738
739 for (n = 0; n < mpdm_size(d) && n < db_height - 1; n++) {
740 mpdm_t l = mpdm_get_i(d, n);
741
742 if (l != NULL) {
743 ansi_db_gotoxy(0, n);
744
745 for (m = 0; m < mpdm_size(l); m++) {
746 int attr;
747 mpdm_t s;
748
749 /* get the attribute and the string */
750 attr = mpdm_ival(mpdm_get_i(l, m++));
751 s = mpdm_get_i(l, m);
752
753 ansi_db_set_attr(attr);
754 ansi_db_print_v(s);
755 }
756
757 ansi_db_set_attr(normal_attr);
758
759 /* delete to end of line */
760 ansi_db_clreol();
761 }
762 }
763
764 mpdm_unref(d);
765
766 return NULL;
767 }
768
769
ansi_tui_getxy(mpdm_t a,mpdm_t ctxt)770 static mpdm_t ansi_tui_getxy(mpdm_t a, mpdm_t ctxt)
771 /* TUI: returns the x and y cursor position */
772 {
773 mpdm_t v;
774 int x, y;
775
776 ansi_db_getxy(&x, &y);
777
778 v = MPDM_A(2);
779 mpdm_ref(v);
780
781 mpdm_set_i(v, MPDM_I(x), 0);
782 mpdm_set_i(v, MPDM_I(y), 1);
783
784 mpdm_unrefnd(v);
785
786 return v;
787 }
788
789
ansi_tui_charat(mpdm_t a,mpdm_t ctxt)790 static mpdm_t ansi_tui_charat(mpdm_t a, mpdm_t ctxt)
791 /* TUI: returns the character at x, y position */
792 {
793 wchar_t s[2];
794 int x, y;
795
796 x = mpdm_ival(mpdm_get_i(a, 0));
797 y = mpdm_ival(mpdm_get_i(a, 1));
798
799 s[0] = ansi_db_charat(x, y);
800 s[1] = L'\0';
801
802 return MPDM_S(s);
803 }
804
805
ansi_register_functions(void)806 static void ansi_register_functions(void)
807 {
808 mpdm_t drv;
809 mpdm_t tui;
810
811 drv = mpdm_get_wcs(mpdm_root(), L"mp_drv");
812
813 mpdm_set_wcs(drv, MPDM_X(ansi_drv_idle), L"idle");
814 mpdm_set_wcs(drv, MPDM_X(ansi_drv_shutdown), L"shutdown");
815 mpdm_set_wcs(drv, MPDM_X(ansi_drv_suspend), L"suspend");
816
817 /* execute tui */
818 tui = mpsl_eval(MPDM_S(L"load('mp_tui.mpsl');"), NULL, NULL);
819
820 mpdm_set_wcs(tui, MPDM_X(ansi_getkey), L"getkey");
821 mpdm_set_wcs(tui, MPDM_X(ansi_tui_addstr), L"addstr");
822 mpdm_set_wcs(tui, MPDM_X(ansi_tui_move), L"move");
823 mpdm_set_wcs(tui, MPDM_X(ansi_tui_attr), L"attr");
824 mpdm_set_wcs(tui, MPDM_X(ansi_tui_refresh), L"refresh");
825 mpdm_set_wcs(tui, MPDM_X(ansi_tui_getxy), L"getxy");
826 mpdm_set_wcs(tui, MPDM_X(ansi_tui_charat), L"charat");
827 mpdm_set_wcs(tui, MPDM_X(ansi_doc_draw), L"doc_draw");
828 }
829
830
ansi_drv_startup(mpdm_t a)831 static mpdm_t ansi_drv_startup(mpdm_t a)
832 {
833 signal(SIGPIPE, SIG_IGN);
834
835 ansi_register_functions();
836
837 ansi_raw_tty(1);
838
839 ansi_sigwinch(0);
840
841 ansi_build_colors();
842
843 /* enter alternate screen */
844 printf("\033[?1049h");
845
846 return NULL;
847 }
848
849
ansi_drv_detect(int * argc,char *** argv)850 int ansi_drv_detect(int *argc, char ***argv)
851 {
852 mpdm_t drv;
853
854 drv = mpdm_set_wcs(mpdm_root(), MPDM_O(), L"mp_drv");
855
856 mpdm_set_wcs(drv, MPDM_S(L"ansi"), L"id");
857 mpdm_set_wcs(drv, MPDM_X(ansi_drv_startup), L"startup");
858
859 return 1;
860 }
861
862
863 #endif /* CONFOPT_ANSI */
864