1 /* s_vcsa.c --
2
3 This file is part of the lzop file compressor.
4
5 Copyright (C) 1996-2017 Markus Franz Xaver Johannes Oberhumer
6 All Rights Reserved.
7
8 lzop and the LZO library are free software; you can redistribute them
9 and/or modify them under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 2 of
11 the License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; see the file COPYING.
20 If not, write to the Free Software Foundation, Inc.,
21 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22
23 Markus F.X.J. Oberhumer
24 <markus@oberhumer.com>
25 http://www.oberhumer.com/opensource/lzop/
26 */
27
28
29 #include "conf.h"
30
31 #if defined(USE_SCREEN) && defined(USE_SCREEN_VCSA)
32
33 #include "screen.h"
34
35 #define this local_this
36
37 #define mask_fg 0x0f
38 #define mask_bg 0xf0
39
40
41 /*************************************************************************
42 // direct screen access ( /dev/vcsaNN )
43 **************************************************************************/
44
45 #include <sys/ioctl.h>
46 #include <termios.h>
47 #if defined(__linux__)
48 # include <linux/kd.h>
49 # include <linux/kdev_t.h>
50 # include <linux/major.h>
51 #endif
52
53
54 struct screen_data_t
55 {
56 int fd;
57 int mode;
58 int page;
59 int cols;
60 int rows;
61 int cursor_x;
62 int cursor_y;
63 unsigned char attr;
64 unsigned char init_attr;
65 unsigned char map[256];
66 unsigned short empty_line[256];
67 };
68
69
70
refresh(screen_t * this)71 static void refresh(screen_t *this)
72 {
73 UNUSED(this);
74 }
75
76
77 static __inline__
make_cell(screen_t * this,int ch,int attr)78 unsigned short make_cell(screen_t *this, int ch, int attr)
79 {
80 return ((attr & 0xff) << 8) | (this->data->map[ch & 0xff] & 0xff);
81 }
82
83
getMode(const screen_t * this)84 static int getMode(const screen_t *this)
85 {
86 return this->data->mode;
87 }
88
89
getPage(const screen_t * this)90 static int getPage(const screen_t *this)
91 {
92 return this->data->page;
93 }
94
95
getRows(const screen_t * this)96 static int getRows(const screen_t *this)
97 {
98 return this->data->rows;
99 }
100
101
getCols(const screen_t * this)102 static int getCols(const screen_t *this)
103 {
104 return this->data->cols;
105 }
106
107
getFg(const screen_t * this)108 static int getFg(const screen_t *this)
109 {
110 return this->data->attr & mask_fg;
111 }
112
113
getBg(const screen_t * this)114 static int getBg(const screen_t *this)
115 {
116 return this->data->attr & mask_bg;
117 }
118
119
setFg(screen_t * this,int fg)120 static void setFg(screen_t *this, int fg)
121 {
122 this->data->attr = (this->data->attr & mask_bg) | (fg & mask_fg);
123 }
124
125
setBg(screen_t * this,int bg)126 static void setBg(screen_t *this, int bg)
127 {
128 this->data->attr = (this->data->attr & mask_fg) | (bg & mask_bg);
129 }
130
131
132 /* private */
gotoxy(screen_t * this,int x,int y)133 static int gotoxy(screen_t *this, int x, int y)
134 {
135 if (x >= 0 && y >= 0 && x < this->data->cols && y < this->data->rows)
136 {
137 if (lseek(this->data->fd, 4 + (x + y * this->data->cols) * 2, SEEK_SET) != -1)
138 {
139 return 0;
140 }
141 }
142 return -1;
143 }
144
145
setCursor(screen_t * this,int x,int y)146 static void setCursor(screen_t *this, int x, int y)
147 {
148 if (gotoxy(this,x,y) == 0)
149 {
150 unsigned char b[2] = { x, y };
151 if (lseek(this->data->fd, 2, SEEK_SET) != -1)
152 write(this->data->fd, b, 2);
153 this->data->cursor_x = x;
154 this->data->cursor_y = y;
155 }
156 }
157
158
getCursor(const screen_t * this,int * x,int * y)159 static void getCursor(const screen_t *this, int *x, int *y)
160 {
161 if (x)
162 *x = this->data->cursor_x;
163 if (y)
164 *y = this->data->cursor_y;
165 }
166
167
putCharAttr(screen_t * this,int ch,int attr,int x,int y)168 static void putCharAttr(screen_t *this, int ch, int attr, int x, int y)
169 {
170 unsigned short a = make_cell(this,ch,attr);
171
172 if (gotoxy(this,x,y) == 0)
173 write(this->data->fd, &a, 2);
174 }
175
176
putChar(screen_t * this,int ch,int x,int y)177 static void putChar(screen_t *this, int ch, int x, int y)
178 {
179 putCharAttr(this,ch,this->data->attr,x,y);
180 }
181
182
putStringAttr(screen_t * this,const char * s,int attr,int x,int y)183 static void putStringAttr(screen_t *this, const char *s, int attr, int x, int y)
184 {
185 while (*s)
186 putCharAttr(this,*s++,attr,x++,y);
187 }
188
189
putString(screen_t * this,const char * s,int x,int y)190 static void putString(screen_t *this, const char *s, int x, int y)
191 {
192 putStringAttr(this,s,this->data->attr,x,y);
193 }
194
195
196 /* private */
getChar(screen_t * this,int * ch,int * attr,int x,int y)197 static void getChar(screen_t *this, int *ch, int *attr, int x, int y)
198 {
199 unsigned short a;
200
201 if (gotoxy(this,x,y) == 0 && read(this->data->fd, &a, 2) == 2)
202 {
203 if (ch)
204 *ch = a & 0xff;
205 if (attr)
206 *attr = (a >> 8) & 0xff;
207 }
208 }
209
210
211 /* private */
init_scrnmap(screen_t * this,int fd)212 static int init_scrnmap(screen_t *this, int fd)
213 {
214 int scrnmap_done = 0;
215 int i;
216
217 #if 1 && defined(GIO_UNISCRNMAP) && defined(E_TABSZ)
218 if (!scrnmap_done)
219 {
220 unsigned short scrnmap[E_TABSZ];
221 if (ioctl(fd, GIO_UNISCRNMAP, scrnmap) == 0)
222 {
223 for (i = 0; i < E_TABSZ; i++)
224 this->data->map[scrnmap[i] & 0xff] = i;
225 scrnmap_done = 1;
226 }
227 }
228 #endif
229 #if 1 && defined(GIO_SCRNMAP) && defined(E_TABSZ)
230 if (!scrnmap_done)
231 {
232 unsigned char scrnmap[E_TABSZ];
233 if (ioctl(fd, GIO_SCRNMAP, scrnmap) == 0)
234 {
235 for (i = 0; i < E_TABSZ; i++)
236 this->data->map[scrnmap[i] & 0xff] = i;
237 scrnmap_done = 1;
238 }
239 }
240 #endif
241
242 return scrnmap_done;
243 }
244
245
init(screen_t * this,int fd)246 static int init(screen_t *this, int fd)
247 {
248 struct stat st;
249
250 if (!this || !this->data)
251 return -1;
252
253 this->data->fd = -1;
254 this->data->mode = -1;
255 this->data->page = 0;
256
257 if (fd < 0 || !acc_isatty(fd))
258 return -1;
259 if (fstat(fd,&st) != 0)
260 return -1;
261
262 /* check if we are running in a virtual console */
263 #if defined(MINOR) && defined(MAJOR) && defined(TTY_MAJOR)
264 if (MAJOR(st.st_rdev) == TTY_MAJOR)
265 {
266 char vc_name[64];
267 unsigned char vc_data[4];
268 int i;
269 int attr;
270 unsigned short a;
271
272 snprintf(vc_name, sizeof(vc_name), "/dev/vcsa%d", (int) MINOR(st.st_rdev));
273 this->data->fd = open(vc_name, O_RDWR);
274 if (this->data->fd != -1)
275 {
276 if (read(this->data->fd, vc_data, 4) == 4)
277 {
278 this->data->mode = 3;
279 this->data->rows = vc_data[0];
280 this->data->cols = vc_data[1];
281 this->data->cursor_x = vc_data[2];
282 this->data->cursor_y = vc_data[3];
283
284 for (i = 0; i < 256; i++)
285 this->data->map[i] = i;
286 i = init_scrnmap(this,this->data->fd) ||
287 init_scrnmap(this,STDIN_FILENO);
288
289 getChar(this,NULL,&attr,this->data->cursor_x,this->data->cursor_y);
290 this->data->init_attr = attr;
291 this->data->attr = attr;
292 a = make_cell(this,' ',attr);
293 for (i = 0; i < 256; i++)
294 this->data->empty_line[i] = a;
295 }
296 else
297 {
298 close(this->data->fd);
299 this->data->fd = -1;
300 }
301 }
302 }
303 #endif
304
305 if (this->data->mode < 0)
306 return -1;
307
308 return 0;
309 }
310
311
finalize(screen_t * this)312 static void finalize(screen_t *this)
313 {
314 if (this->data->fd != -1)
315 (void) close(this->data->fd);
316 }
317
318
updateLineN(screen_t * this,const void * line,int y,int len)319 static void updateLineN(screen_t *this, const void *line, int y, int len)
320 {
321 if (len > 0 && len <= 2*this->data->cols && gotoxy(this,0,y) == 0)
322 {
323 int i;
324 unsigned char new_line[len];
325 unsigned char *l1 = new_line;
326 const unsigned char *l2 = (const unsigned char *) line;
327
328 for (i = 0; i < len; i += 2)
329 {
330 *l1++ = *l2++;
331 *l1++ = this->data->map[*l2++];
332 }
333 write(this->data->fd, new_line, len);
334 }
335 }
336
337
clearLine(screen_t * this,int y)338 static void clearLine(screen_t *this, int y)
339 {
340 if (gotoxy(this,0,y) == 0)
341 write(this->data->fd, this->data->empty_line, 2*this->data->cols);
342 }
343
344
clear(screen_t * this)345 static void clear(screen_t *this)
346 {
347 int y;
348
349 for (y = 0; y < this->data->rows; y++)
350 clearLine(this,y);
351 }
352
353
scrollUp(screen_t * this,int lines)354 static int scrollUp(screen_t *this, int lines)
355 {
356 int sr = this->data->rows;
357 int sc = this->data->cols;
358 int y;
359
360 if (lines <= 0)
361 return 0;
362 if (lines >= sr)
363 clear(this);
364 else
365 {
366 unsigned short buf[ (sr-lines)*sc ];
367
368 gotoxy(this,0,lines);
369 read(this->data->fd, buf, sizeof(buf));
370 gotoxy(this,0,0);
371 write(this->data->fd, buf, sizeof(buf));
372
373 for (y = sr - lines; y < sr; y++)
374 clearLine(this,y);
375 }
376 return lines;
377 }
378
379
getCursorShape(const screen_t * this)380 static int getCursorShape(const screen_t *this)
381 {
382 UNUSED(this);
383 return 0;
384 }
385
386
setCursorShape(screen_t * this,int shape)387 static void setCursorShape(screen_t *this, int shape)
388 {
389 UNUSED(this);
390 UNUSED(shape);
391 }
392
393
kbhit(screen_t * this)394 static int kbhit(screen_t *this)
395 {
396 const int fd = STDIN_FILENO;
397 const unsigned long usec = 0;
398 struct timeval tv;
399 fd_set fds;
400
401 UNUSED(this);
402 FD_ZERO(&fds);
403 FD_SET(fd, &fds);
404 tv.tv_sec = usec / 1000000;
405 tv.tv_usec = usec % 1000000;
406 return (select(fd + 1, &fds, NULL, NULL, &tv) > 0);
407 }
408
409
intro(screen_t * this,void (* show_frames)(screen_t *))410 static int intro(screen_t *this, void (*show_frames)(screen_t *) )
411 {
412 int shape;
413 struct termios term_old, term_new;
414 int term_r;
415
416 if ((this->data->init_attr & mask_bg) != BG_BLACK)
417 return 0;
418
419 term_r = tcgetattr(STDIN_FILENO, &term_old);
420 if (term_r == 0)
421 {
422 term_new = term_old;
423 term_new.c_lflag &= ~(ISIG | ICANON | ECHO);
424 tcsetattr(STDIN_FILENO, TCSANOW, &term_new);
425 }
426
427 shape = getCursorShape(this);
428 setCursorShape(this,0x2000);
429 show_frames(this);
430 if (this->data->rows > 24)
431 setCursor(this,this->data->cursor_x,this->data->cursor_y+1);
432 setCursorShape(this,shape);
433
434 while (kbhit(this))
435 (void) getchar();
436 if (term_r == 0)
437 tcsetattr(STDIN_FILENO, TCSANOW, &term_old);
438
439 return 1;
440 }
441
442
443 static const screen_t driver =
444 {
445 sobject_destroy,
446 finalize,
447 init,
448 refresh,
449 getMode,
450 getPage,
451 getRows,
452 getCols,
453 getFg,
454 getBg,
455 getCursor,
456 getCursorShape,
457 setFg,
458 setBg,
459 setCursor,
460 setCursorShape,
461 putChar,
462 putCharAttr,
463 putString,
464 putStringAttr,
465 clear,
466 clearLine,
467 updateLineN,
468 scrollUp,
469 kbhit,
470 intro,
471 (struct screen_data_t *) 0
472 };
473
474
475 /* public constructor */
screen_vcsa_construct(void)476 screen_t *screen_vcsa_construct(void)
477 {
478 return sobject_construct(&driver,sizeof(*driver.data));
479 }
480
481
482 #endif /* defined(USE_SCREEN) && defined(USE_SCREEN_VCSA) */
483
484
485 /* vim:set ts=4 sw=4 et: */
486