1 Star 1 Fork 0

OnlyVersion/upx

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
s_vcsa.cpp 13.68 KB
一键复制 编辑 原始数据 按行查看 历史
Markus F.X.J. Oberhumer 提交于 2017-01-03 12:02 . Welcome 2017.
/* s_vcsa.cpp -- Linux /dev/vcsa screen driver
This file is part of the UPX executable compressor.
Copyright (C) 1996-2017 Markus Franz Xaver Johannes Oberhumer
Copyright (C) 1996-2017 Laszlo Molnar
All Rights Reserved.
UPX and the UCL library are free software; you can redistribute them
and/or modify them under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; see the file COPYING.
If not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Markus F.X.J. Oberhumer Laszlo Molnar
*/
#include "conf.h"
#if (USE_SCREEN) && (USE_SCREEN_VCSA)
#include "screen.h"
#define this self
#define mask_fg 0x0f
#define mask_bg 0xf0
/* #define USE_SCROLLBACK 1 */
/*************************************************************************
// direct screen access ( /dev/vcsaNN )
**************************************************************************/
#include <sys/ioctl.h>
#include <sys/select.h>
#include <termios.h>
#if defined(__linux__)
#include <linux/kd.h>
#include <linux/kdev_t.h>
#include <linux/major.h>
#endif
#define Cell upx_uint16_t
struct screen_data_t {
int fd;
int mode;
int page;
int cols;
int rows;
int cursor_x;
int cursor_y;
int scroll_counter;
unsigned char attr;
unsigned char init_attr;
unsigned char map[256];
Cell empty_line[256];
#if USE_SCROLLBACK
/* scrollback buffer */
Cell sb_buf[32][256];
int sb_size;
int sb_base;
int sb_sp;
#endif /* USE_SCROLLBACK */
};
#if USE_SCROLLBACK
static __inline__ void sb_add(screen_t *this, int *val, int inc) {
*val = (*val + inc) & (this->data->sb_size - 1);
}
static void sb_push(screen_t *this, const Cell *line, int len) {
memcpy(this->data->sb_buf[this->data->sb_sp], line, len);
sb_add(this, &this->data->sb_sp, 1);
if (this->data->sb_sp == this->data->sb_base)
sb_add(this, &this->data->sb_base, 1);
}
static const Cell *sb_pop(screen_t *this) {
if (this->data->sb_sp == this->data->sb_base)
return NULL;
sb_add(this, &this->data->sb_sp, -1);
return this->data->sb_buf[this->data->sb_sp];
}
#endif /* USE_SCROLLBACK */
static void refresh(screen_t *this) { UNUSED(this); }
static __inline__ Cell make_cell(screen_t *this, int ch, int attr) {
return ((attr & 0xff) << 8) | (this->data->map[ch & 0xff] & 0xff);
}
static int getMode(const screen_t *this) { return this->data->mode; }
static int getPage(const screen_t *this) { return this->data->page; }
static int getRows(const screen_t *this) { return this->data->rows; }
static int getCols(const screen_t *this) { return this->data->cols; }
static int isMono(const screen_t *this) {
/* FIXME */
UNUSED(this);
return 0;
}
static int getFg(const screen_t *this) { return this->data->attr & mask_fg; }
static int getBg(const screen_t *this) { return this->data->attr & mask_bg; }
static void setFg(screen_t *this, int fg) {
this->data->attr = (this->data->attr & mask_bg) | (fg & mask_fg);
}
static void setBg(screen_t *this, int bg) {
this->data->attr = (this->data->attr & mask_fg) | (bg & mask_bg);
}
/* private */
static int gotoxy(screen_t *this, int x, int y) {
if (x >= 0 && y >= 0 && x < this->data->cols && y < this->data->rows) {
if (lseek(this->data->fd, 4 + (x + y * this->data->cols) * 2, SEEK_SET) != -1) {
return 0;
}
}
return -1;
}
static void setCursor(screen_t *this, int x, int y) {
if (gotoxy(this, x, y) == 0) {
unsigned char b[2] = {x, y};
if (lseek(this->data->fd, 2, SEEK_SET) != -1)
write(this->data->fd, b, 2);
this->data->cursor_x = x;
this->data->cursor_y = y;
}
}
static void getCursor(const screen_t *this, int *x, int *y) {
int cx = this->data->cursor_x;
int cy = this->data->cursor_y;
#if 1
if (lseek(this->data->fd, 2, SEEK_SET) != -1) {
unsigned char b[2];
if (read(this->data->fd, b, 2) == 2) {
if (b[0] < this->data->cols && b[1] < this->data->rows) {
cx = b[0];
cy = b[1];
}
}
}
#endif
if (x)
*x = cx;
if (y)
*y = cy;
}
static void putCharAttr(screen_t *this, int ch, int attr, int x, int y) {
Cell a = make_cell(this, ch, attr);
if (gotoxy(this, x, y) == 0)
write(this->data->fd, &a, 2);
}
static void putChar(screen_t *this, int ch, int x, int y) {
putCharAttr(this, ch, this->data->attr, x, y);
}
static void putStringAttr(screen_t *this, const char *s, int attr, int x, int y) {
assert((int) strlen(s) <= 256);
assert(x + (int) strlen(s) <= this->data->cols);
while (*s)
putCharAttr(this, *s++, attr, x++, y);
}
static void putString(screen_t *this, const char *s, int x, int y) {
putStringAttr(this, s, this->data->attr, x, y);
}
/* private */
static void getChar(screen_t *this, int *ch, int *attr, int x, int y) {
upx_uint16_t a;
if (gotoxy(this, x, y) == 0 && read(this->data->fd, &a, 2) == 2) {
if (ch)
*ch = a & 0xff;
if (attr)
*attr = (a >> 8) & 0xff;
}
}
/* private */
static int init_scrnmap(screen_t *this, int fd) {
int scrnmap_done = 0;
int i;
#if 1 && defined(GIO_UNISCRNMAP) && defined(E_TABSZ)
if (!scrnmap_done) {
upx_uint16_t scrnmap[E_TABSZ];
if (ioctl(fd, GIO_UNISCRNMAP, scrnmap) == 0) {
for (i = 0; i < E_TABSZ; i++)
this->data->map[scrnmap[i] & 0xff] = i;
scrnmap_done = 1;
}
}
#endif
#if 1 && defined(GIO_SCRNMAP) && defined(E_TABSZ)
if (!scrnmap_done) {
unsigned char scrnmap[E_TABSZ];
if (ioctl(fd, GIO_SCRNMAP, scrnmap) == 0) {
for (i = 0; i < E_TABSZ; i++)
this->data->map[scrnmap[i] & 0xff] = i;
scrnmap_done = 1;
}
}
#endif
return scrnmap_done;
}
static int init(screen_t *this, int fd) {
struct stat st;
if (!this || !this->data)
return -1;
this->data->fd = -1;
this->data->mode = -1;
this->data->page = 0;
#if USE_SCROLLBACK
this->data->sb_size = 32;
this->data->sb_base = 0;
this->data->sb_sp = 0;
#endif
if (fd < 0 || !acc_isatty(fd))
return -1;
if (fstat(fd, &st) != 0)
return -1;
/* check if we are running in a virtual console */
#if defined(MINOR) && defined(MAJOR) && defined(TTY_MAJOR)
if (MAJOR(st.st_rdev) == TTY_MAJOR) {
char vc_name[64];
unsigned char vc_data[4];
int i;
int attr;
Cell a;
upx_snprintf(vc_name, sizeof(vc_name), "/dev/vcsa%d", (int) MINOR(st.st_rdev));
this->data->fd = open(vc_name, O_RDWR);
if (this->data->fd == -1) {
upx_snprintf(vc_name, sizeof(vc_name), "/dev/vcc/a%d", (int) MINOR(st.st_rdev));
this->data->fd = open(vc_name, O_RDWR);
}
if (this->data->fd != -1) {
if (read(this->data->fd, vc_data, 4) == 4) {
this->data->mode = 3;
this->data->rows = vc_data[0];
this->data->cols = vc_data[1];
this->data->cursor_x = vc_data[2];
this->data->cursor_y = vc_data[3];
for (i = 0; i < 256; i++)
this->data->map[i] = i;
i = init_scrnmap(this, this->data->fd) || init_scrnmap(this, STDIN_FILENO);
getChar(this, NULL, &attr, this->data->cursor_x, this->data->cursor_y);
this->data->init_attr = attr;
this->data->attr = attr;
a = make_cell(this, ' ', attr);
for (i = 0; i < 256; i++)
this->data->empty_line[i] = a;
} else {
close(this->data->fd);
this->data->fd = -1;
}
}
}
#endif
if (this->data->mode < 0)
return -1;
return 0;
}
static void finalize(screen_t *this) {
if (this->data->fd != -1)
(void) close(this->data->fd);
}
static void updateLineN(screen_t *this, const void *line, int y, int len) {
if (len > 0 && len <= 2 * this->data->cols && gotoxy(this, 0, y) == 0) {
int i;
unsigned char new_line[len];
unsigned char *l1 = new_line;
const unsigned char *l2 = (const unsigned char *) line;
for (i = 0; i < len; i += 2) {
*l1++ = *l2++;
*l1++ = this->data->map[*l2++];
}
write(this->data->fd, new_line, len);
}
}
static void clearLine(screen_t *this, int y) {
if (gotoxy(this, 0, y) == 0)
write(this->data->fd, this->data->empty_line, 2 * this->data->cols);
}
static void clear(screen_t *this) {
int y;
for (y = 0; y < this->data->rows; y++)
clearLine(this, y);
}
static int scrollUp(screen_t *this, int lines) {
int sr = this->data->rows;
int sc = this->data->cols;
int y;
if (lines <= 0 || lines > sr)
return 0;
#if USE_SCROLLBACK
/* copy to scrollback buffer */
for (y = 0; y < lines; y++) {
Cell buf[sc];
gotoxy(this, 0, y);
read(this->data->fd, buf, sizeof(buf));
sb_push(this, buf, sizeof(buf));
}
#endif
/* move screen up */
if (lines < sr) {
Cell buf[(sr - lines) * sc];
gotoxy(this, 0, lines);
read(this->data->fd, buf, sizeof(buf));
gotoxy(this, 0, 0);
write(this->data->fd, buf, sizeof(buf));
}
/* fill in blank lines at bottom */
for (y = sr - lines; y < sr; y++)
clearLine(this, y);
this->data->scroll_counter += lines;
return lines;
}
static int scrollDown(screen_t *this, int lines) {
int sr = this->data->rows;
int sc = this->data->cols;
int y;
if (lines <= 0 || lines > sr)
return 0;
/* move screen down */
if (lines < sr) {
Cell buf[(sr - lines) * sc];
gotoxy(this, 0, 0);
read(this->data->fd, buf, sizeof(buf));
gotoxy(this, 0, lines);
write(this->data->fd, buf, sizeof(buf));
}
/* copy top lines from scrollback buffer */
for (y = lines; --y >= 0;) {
#if USE_SCROLLBACK
const Cell *buf = sb_pop(this);
if (buf == NULL)
clearLine(this, y);
else
updateLineN(this, buf, y, sc * 2);
#else
clearLine(this, y);
#endif
}
this->data->scroll_counter -= lines;
return lines;
}
static int getScrollCounter(const screen_t *this) { return this->data->scroll_counter; }
static int getCursorShape(const screen_t *this) {
UNUSED(this);
return 0;
}
static void setCursorShape(screen_t *this, int shape) {
UNUSED(this);
UNUSED(shape);
}
static int kbhit(screen_t *this) {
const int fd = STDIN_FILENO;
const unsigned usec = 0;
struct timeval tv;
fd_set fds;
UNUSED(this);
FD_ZERO(&fds);
FD_SET(fd, &fds);
tv.tv_sec = usec / 1000000;
tv.tv_usec = usec % 1000000;
return (select(fd + 1, &fds, NULL, NULL, &tv) > 0);
}
static int intro(screen_t *this, void (*show_frames)(screen_t *)) {
int shape;
struct termios term_old, term_new;
int term_r;
if ((this->data->init_attr & mask_bg) != BG_BLACK)
return 0;
term_r = tcgetattr(STDIN_FILENO, &term_old);
if (term_r == 0) {
term_new = term_old;
term_new.c_lflag &= ~(ISIG | ICANON | ECHO);
tcsetattr(STDIN_FILENO, TCSANOW, &term_new);
}
shape = getCursorShape(this);
setCursorShape(this, 0x2000);
show_frames(this);
if (this->data->rows > 24)
setCursor(this, this->data->cursor_x, this->data->cursor_y + 1);
setCursorShape(this, shape);
while (kbhit(this))
(void) fgetc(stdin);
if (term_r == 0)
tcsetattr(STDIN_FILENO, TCSANOW, &term_old);
return 1;
}
static const screen_t driver = {sobject_destroy,
finalize,
0, /* atExit */
init,
refresh,
getMode,
getPage,
getRows,
getCols,
isMono,
getFg,
getBg,
getCursor,
getCursorShape,
setFg,
setBg,
setCursor,
setCursorShape,
0, /* hideCursor */
putChar,
putCharAttr,
putString,
putStringAttr,
clear,
clearLine,
updateLineN,
scrollUp,
scrollDown,
getScrollCounter,
kbhit,
intro,
(struct screen_data_t *) 0};
/* public constructor */
screen_t *screen_vcsa_construct(void) { return sobject_construct(&driver, sizeof(*driver.data)); }
#endif /* (USE_SCREEN) && (USE_SCREEN_VCSA) */
/* vim:set ts=4 sw=4 et: */
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/OnlyVersion/upx.git
[email protected]:OnlyVersion/upx.git
OnlyVersion
upx
upx
master

搜索帮助