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