fixed: tried to free mapped buffer, unmap if mapped, free otherwise,
[visor] / visor / src / term.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <signal.h>
5 #include <errno.h>
6 #include <stdarg.h>
7 #include <unistd.h>
8 #include <fcntl.h>
9 #include <termios.h>
10 #include <sys/ioctl.h>
11 #include "term.h"
12
13 static void sighandler(int s);
14
15 static int term_width, term_height;
16 static int ttyfd = -1;
17 static int selfpipe[2];
18 static struct termios saved_term;
19
20 static void (*cb_resized)(int, int);
21
22
23 int term_init(const char *ttypath)
24 {
25         struct termios term;
26         struct winsize winsz;
27
28         if((ttyfd = open(ttypath ? ttypath : "/dev/tty", O_RDWR)) == -1) {
29                 perror("failed to open /dev/tty");
30                 return -1;
31         }
32         if(tcgetattr(ttyfd, &term) == -1) {
33                 perror("failed to get terminal attr");
34                 return -1;
35         }
36         saved_term = term;
37         term.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
38         term.c_oflag &= ~OPOST;
39         term.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
40         term.c_cflag = (term.c_cflag & ~(CSIZE | PARENB)) | CS8;
41
42         if(tcsetattr(ttyfd, TCSAFLUSH, &term) == -1) {
43                 perror("failed to change terminal attributes");
44                 return -1;
45         }
46
47         ioctl(1, TIOCGWINSZ, &winsz);
48         term_width = winsz.ws_col;
49         term_height = winsz.ws_row;
50
51         pipe(selfpipe);
52
53         signal(SIGWINCH, sighandler);
54         return 0;
55 }
56
57 void term_cleanup(void)
58 {
59         tcsetattr(ttyfd, TCSAFLUSH, &saved_term);
60         close(ttyfd);
61         ttyfd = -1;
62 }
63
64 void term_getsize(int *width, int *height)
65 {
66         *width = term_width;
67         *height = term_height;
68 }
69
70 void term_resize_func(void (*func)(int, int))
71 {
72         cb_resized = func;
73 }
74
75
76 static char termbuf[1024];
77 static int termbuf_len;
78
79 void term_send(const char *s, int size)
80 {
81         if(size >= sizeof termbuf) {
82                 /* too large, just flush the buffer and write directly to the tty */
83                 term_flush();
84                 write(ttyfd, s, size);
85         } else {
86                 if(size >= sizeof termbuf - termbuf_len) {
87                         term_flush();
88                 }
89                 memcpy(termbuf + termbuf_len, s, size);
90                 termbuf_len += size;
91         }
92 }
93
94 void term_putchar(char c)
95 {
96         term_send(&c, 1);
97 }
98
99 void term_puts(const char *s)
100 {
101         term_send(s, strlen(s));
102 }
103
104 void term_printf(const char *fmt, ...)
105 {
106         static char *buf;
107         static long bufsz;
108         va_list ap;
109         long len;
110
111         if(!buf) {
112                 bufsz = 512;
113                 if(!(buf = malloc(bufsz))) {
114                         return;
115                 }
116         }
117
118         for(;;) {
119                 va_start(ap, fmt);
120                 len = vsnprintf(buf, bufsz, fmt, ap);
121                 va_end(ap);
122
123                 if(len < bufsz) break;
124                 if(len < 0) {
125                         void *tmp;
126                         long n = bufsz << 1;
127                         if(!(tmp = realloc(buf, n))) {
128                                 break;  /* if realloc fails, will result in truncated output */
129                         }
130                 }
131         }
132
133         term_send(buf, len);
134 }
135
136 void term_flush(void)
137 {
138         if(termbuf_len > 0) {
139                 write(ttyfd, termbuf, termbuf_len);
140                 termbuf_len = 0;
141         }
142 }
143
144 void term_clear(void)
145 {
146         term_puts("\033[2J");
147 }
148
149 void term_cursor(int show)
150 {
151         term_printf("\033[?25%c", show ? 'h' : 'l');
152 }
153
154 void term_setcursor(int row, int col)
155 {
156         term_printf("\033[%d;%dH", row + 1, col + 1);
157 }
158
159 int term_getchar(void)
160 {
161         int res;
162         char c;
163         while((res = read(ttyfd, &c, 1)) < 0 && errno == EINTR);
164         if(res <= 0) return -1;
165         return c;
166 }
167
168
169 static void sighandler(int s)
170 {
171         struct winsize winsz;
172
173         signal(s, sighandler);
174
175         switch(s) {
176         case SIGWINCH:
177                 ioctl(1, TIOCGWINSZ, &winsz);
178                 term_width = winsz.ws_col;
179                 term_height = winsz.ws_row;
180                 /* redraw */
181                 break;
182
183         default:
184                 break;
185         }
186 }