gcc says those values are out of bounds
[apps/madtty.git] / demo / boxshell.c
1 /* Just a simple example program that creates a terminal in a frame
2  * and lets the user interact with it.
3  *
4  * To compile:
5  *    gcc -o boxshell boxshell.c $(pkg-config madtty --cflags --libs)
6  */
7
8 #include <ncurses.h>
9
10 #include <fcntl.h>
11 #include <locale.h>
12 #include <signal.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <sys/ioctl.h>
16 #include <sys/time.h>
17 #include <termios.h>
18 #include <time.h>
19
20 #include <madtty/madtty.h>
21
22 static int getout = 0, sigwinch = 0;
23 static int screen_w, screen_h;
24 static WINDOW *term_win;
25 static struct timeval const slice = { 0, 1000 * 1000 / 100 };
26
27 void handler(int signo)
28 {
29     switch (signo) {
30       case SIGCHLD:
31         getout = 1;
32         break;
33       case SIGWINCH:
34         sigwinch = 1;
35         break;
36     }
37 }
38
39 static struct timeval timeval_add(struct timeval a, struct timeval b)
40 {
41     int usec = a.tv_usec + b.tv_usec;
42     a.tv_sec += b.tv_sec;
43     while (usec > 1000 * 1000) {
44         a.tv_sec += 1;
45         usec -= 1000 * 1000;
46     }
47     a.tv_usec = usec;
48     return a;
49 }
50
51 static int is_expired(struct timeval now, struct timeval expiry)
52 {
53     return now.tv_sec > expiry.tv_sec
54         || (now.tv_sec == expiry.tv_sec && now.tv_usec > expiry.tv_usec);
55 }
56
57 int main(void)
58 {
59     madtty_t *rt;
60     int dirty = 0, pty;
61     struct timeval next;
62
63     signal(SIGCHLD, handler);
64     signal(SIGWINCH, handler);
65
66     setlocale(LC_ALL, "");
67     initscr();
68     start_color();
69     noecho();
70     raw();
71     nodelay(stdscr, TRUE);
72     keypad(stdscr, TRUE);
73     curs_set(0);
74     ESCDELAY=50;
75     madtty_init_vt100_graphics();
76     madtty_init_colors();
77     getmaxyx(stdscr, screen_h, screen_w);
78
79     /* create a window with a frame */
80     term_win = newwin(screen_h - 2, screen_w - 2, 1, 1);
81     rt = madtty_create(screen_h - 2, screen_w -2);
82     {
83         const char *path = getenv("SHELL") ?: "/bin/sh";
84         const char *args[] = { path, "--login", NULL};
85
86         madtty_forkpty(rt, path, args, &pty);
87     }
88
89     /* keep reading keypresses from the user and passing them to the terminal;
90      * also, redraw the terminal to the window at each iteration */
91     gettimeofday(&next, NULL);
92     while (!getout) {
93         struct timeval tv = { 0, 1000 * 1000 / 100 };
94         fd_set rfds;
95         int ch;
96
97         FD_ZERO(&rfds);
98         FD_SET(0, &rfds);
99         FD_SET(pty, &rfds);
100
101         if (select(pty + 1, &rfds, NULL, NULL, &tv) > 0) {
102             if (FD_ISSET(pty, &rfds)) {
103                 madtty_process(rt);
104                 dirty = 1;
105             }
106         }
107
108         if (sigwinch) {
109             int fd, cols = -1, rows = -1;
110             struct winsize w;
111
112             if ((fd = open("/dev/tty", O_RDONLY)) != -1) {
113                 if (ioctl(fd, TIOCGWINSZ, &w) != -1) {
114                     rows = w.ws_row;
115                     cols = w.ws_col;
116                 }
117                 close(fd);
118             }
119             if (rows <= 0) {
120                 rows = atoi(getenv("LINES") ?: "24");
121             }
122             if (cols <= 0) {
123                 cols = atoi(getenv("COLUMNS") ?: "80");
124             }
125
126             resizeterm(rows, cols);
127             madtty_resize(rt, rows - 2, cols - 2);
128             wresize(term_win, rows - 2, cols - 2);
129             sigwinch = 0;
130             erase();
131         }
132
133         while ((ch = getch()) != ERR) {
134             madtty_keypress(rt, ch); /* pass the keypress for handling */
135             dirty = 1;
136         }
137
138         gettimeofday(&tv, NULL);
139         if (dirty && is_expired(tv, next)) {
140             madtty_draw(rt, term_win, 0, 0);
141             wrefresh(term_win);
142             dirty = 0;
143             next = timeval_add(tv, slice);
144         }
145     }
146
147     endwin();
148     return 0;
149 }