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