📄 zhcon.cpp
字号:
// vi:ts=4:shiftwidth=4:expandtab/*************************************************************************** zhcon.cpp - description ------------------- begin : Fri Mar 23 2001 copyright : (C) 2001 by ejoy email : ejoy@users.sourceforge.net ***************************************************************************//*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it 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. * * * ***************************************************************************/#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <iostream>#include <unistd.h>#include <cstdlib>#include <cstdio>#include <sys/ioctl.h>#if defined(linux) #include <linux/limits.h> #include <linux/kd.h> #include <linux/vt.h> #include <pty.h>#elif defined(__FreeBSD__) #include <termios.h> //#include <machine/console.h> #include <sys/consio.h> #include <libutil.h> #define TCSETA TIOCSETA#endif#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <signal.h>#include <pwd.h>#include <stdexcept>#include <algorithm>#include <locale.h>#include "global.h"#include "console.h"#include "encfilter.h"#include "inputclient.h"#include "inputmanager.h"#include "nativeinputserver.h"#ifdef HAVE_UNICON_LIB #include "uniconinputserver.h"#endif// for termcap, must include after gpm.h, why?#include <term.h>#include "gbkdecoder.h"#include "gbdecoder.h"#include "big5decoder.h"#include "gb2big5decoder.h"#include "big52gbdecoder.h"#include "jisdecoder.h"#include "kscdecoder.h"#include "configfile.h"//#include "fade.h"#include "zhcon.h"#include "basefont.h"#include "encfilter.h"#include "cmdline.h"//#include "popwin.h"BaseFont* gpHzFont;BaseFont* gpAscFont;#ifndef NDEBUG#include "debug.h"ofstream debug("debug");#endifZhcon* Zhcon::mpZhcon = NULL;int Zhcon::mTtyPid = 0;Zhcon::STATE Zhcon::mState = STOP;void Zhcon::SignalVtLeave(int signo) { if(Zhcon::mpZhcon != NULL) mpZhcon->VtDoLeave();}void Zhcon::SignalVtEnter(int signo) { if(Zhcon::mpZhcon != NULL) mpZhcon->VtDoEnter();}Zhcon::Zhcon(int argc, char* argv[]):mpCon(NULL),mpInputManager(NULL){ Zhcon::mpZhcon = this; mConFd = mTtyFd = -1; /* let's call our CMDLINE Parser */ if (cmdline_parser(argc, argv, &mArgs) != 0) { cmdline_parser_print_help(); throw runtime_error("fail to parse command line arguments"); } if (mArgs.utf8_flag) UseEncodingFilter = 1;}Zhcon::~Zhcon() { CleanUp(); Zhcon::mpZhcon = NULL;}void Zhcon::Init() { //reading config file string cfgfile = getenv("HOME"); cfgfile += "/.zhconrc"; if (access(cfgfile.c_str(), R_OK) != 0) cfgfile = "/etc/zhcon.conf"; //for debug,a pause enable us to attach zhcon's pid in gdb //char c;cin>>c; ConfigFile f(cfgfile.c_str()); //the InitXXX sequence is important,do not change //unless you know what you are doing InitTty(); // set blank line height, must before init font InitGraphDev(f); GraphMode(); seteuid(getuid()); InitLocale(f); // include init font InitCon(f); InitMisc(f); VtSignalLeave(); InstallSignal(); ForkPty(); // if setlocale run before forkpty, it cause FreeBSD hang SetEncode(mDefaultEncode, mDefaultEncode); InitInputManager(f); if (f.GetOption("startupmsg",true)) StartupMsg();}void Zhcon::Run() { InputEvt evt; Encode e; int t = 0;// fadeout();// fadein(); mState = RUNNING; while (mState == RUNNING) { mpCon->CursorBlink(); mpInputManager->Process(evt); gpScreen->Update(); // force ggi to update screen if (evt.oper != InputEvt::Nothing) { DoInputEvt(evt); continue; } if (++t < 10 || mAutoEncode == MANUAL) continue; t = 0; e = mpCon->DetectBufferEncode(); switch (e) { case ASCII: SetEncode(mDefaultEncode, mDefaultEncode); break; case GB2312: SetEncode(GB2312, mAutoEncode == AUTO_BIG5 ? BIG5 : GB2312); break; case BIG5: SetEncode(BIG5, mAutoEncode == AUTO_GB ? GB2312 : BIG5); break; default: assert(!"Wrong encode!"); } } //while}void Zhcon::DoInputEvt(InputEvt &evt) { switch (evt.oper) { case InputEvt::SetEnco: switch (evt.sub) { case 1: SetEncode(GB2312, GB2312); break; case 2: SetEncode(GBK, GBK); break; case 3: SetEncode(BIG5, BIG5); break; case 4: SetEncode(JIS, JIS); break; case 5: SetEncode(KSC, KSC); break; default: break; } break; case InputEvt::AutoEncoSwitch: switch (mAutoEncode) { case AUTO: mAutoEncode = AUTO_GB; break; case AUTO_GB: mAutoEncode = AUTO_BIG5; break; case AUTO_BIG5: mAutoEncode = MANUAL; break; case MANUAL: mAutoEncode = AUTO; break; } mpInputManager->Redraw(); Beep(); break; default: break; }}//fork a new pty to run user's shellvoid Zhcon::ForkPty() { char name[50]; mTtyPid = forkpty(&mTtyFd, name, NULL, NULL); if (mTtyPid == -1) throw runtime_error("forkpty fail!"); ioctl(0, TIOCSCTTY, 0); if (mTtyPid == 0) { //child struct passwd *userpd; if ((userpd = getpwuid(getuid())) == NULL) throw runtime_error("can not get user's shell!"); /* close all opened file */ int open_max = sysconf(_SC_OPEN_MAX); for (int i = 3; i < open_max; i++) close(i); setsid(); // seteuid(getuid()); /* for security */ //TODO: handle error condition if (mArgs.inputs_num > 0) { // the second arg of execvp must be terminated by a NULL pointer // we have to create a new one with NULL pointer at the end char** args = (char**)malloc(sizeof(char*)*(mArgs.inputs_num+1)); for (size_t i = 0; i < mArgs.inputs_num; ++i) args[i] = mArgs.inputs[i]; args[mArgs.inputs_num] = NULL; cout << "Executing ["; for (size_t i = 0; i < mArgs.inputs_num; ++i) cout << ' ' << args[i] << ' '; cout << ']' << endl; execvp(args[0], args); } else execlp(userpd->pw_shell, userpd->pw_shell, (char *) 0); exit(0); }}void Zhcon::InstallSignal() { struct sigaction act; act.sa_handler = SignalHandle; act.sa_flags = 0; sigemptyset(&act.sa_mask); sigaction(SIGHUP, &act, NULL); sigaction(SIGINT, &act, NULL); sigaction(SIGQUIT, &act, NULL); sigaction(SIGILL, &act, NULL); sigaction(SIGABRT, &act, NULL); sigaction(SIGIOT, &act, NULL); sigaction(SIGBUS, &act, NULL); sigaction(SIGFPE, &act, NULL); sigaction(SIGTERM, &act, NULL); act.sa_handler = &SignalChild; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGCHLD, &act, NULL); // act.sa_handler = &SignalAlarm; // sigemptyset(&act.sa_mask); // act.sa_flags = 0; // sigaction(SIGALRM, &act, NULL);}//do some clean up before quitvoid Zhcon::CleanUp() { struct sigaction act; /* done in procress and block all serious signal to prevent interrupt */ act.sa_handler = SIG_IGN; act.sa_flags = 0; sigemptyset(&act.sa_mask); sigaction(SIGHUP, &act, NULL); sigaction(SIGINT, &act, NULL); sigaction(SIGQUIT, &act, NULL); sigaction(SIGILL, &act, NULL); sigaction(SIGABRT, &act, NULL); sigaction(SIGIOT, &act, NULL); sigaction(SIGBUS, &act, NULL); sigaction(SIGFPE, &act, NULL); VtSignalClean();#if defined(__FreeBSD__) ioctl(0, VT_RELDISP, 1);#endif GraphDev::Close(); delete gpAscFont; delete gpHzFont; delete gpDecoder; delete mpCon; delete mpInputManager; if (mConFd != -1) { // need restore signal ? tcsetattr(mConFd, TCSAFLUSH, &mOldTermios); // restore console blanking#if defined(linux) write(mConFd, "\033[9;10]",7); // default 10 minutes#elif defined(__FreeBSD__) int BlankTime = 5; // default 5 minutes ioctl(mConFd, CONS_BLANKTIME, &BlankTime);#endif ioctl(mConFd, KDSETMODE, KD_TEXT); // special for vga ioctl(mConFd, TIOCSWINSZ, &mOldWinSize); // for mouse, keep text mode clean // write(mConFd, "\n", 1); // make visible cursor, use termcap "ve" instead //write(mConFd, "\E[?25h\E[?0c", 11); if (mpCapCursorOn) write(mConFd, mpCapCursorOn, strlen(mpCapCursorOn)); close(mConFd); } if (mArgs.utf8_flag) CleanupEncodingFilter(); setenv("LC_ALL", mOldLocale.c_str(), 1);}char Zhcon::mCapBuf[512] = {0};char* Zhcon::mpCapClearScr = NULL;char* Zhcon::mpCapCursorOff = NULL;char* Zhcon::mpCapCursorOn = NULL;void Zhcon::InitTty() { // Using throw cause core dump when call destruct if (!isatty(fileno(stdout))) { printf("This is an interactive api, don't redirect stdout.\r\n"); exit(1); } char *TtyName = ttyname(fileno(stdout)); if (!TtyName) { printf("Can not get current tty name.\r\n"); exit(1); } if (!(strncmp("/dev/tty", TtyName, 8) == 0 || strncmp("/dev/vc/", TtyName, 8) == 0)) { fprintf(stderr, "warning!!!\n"); fprintf(stderr, "%s is not real tty or vc, are your running under X-Window?\n", TtyName);#ifndef HAVE_GGI_LIB fprintf(stderr, "libggi support not complied in, can not run under X-Window, now quit\n"); exit(1);#endif } mConFd = open(TtyName, O_RDWR); if (mConFd == -1) throw runtime_error("Can not open console!"); if (tcgetattr(mConFd, &mOldTermios) < 0) throw runtime_error("Can't get console termios."); struct termios t; t = mOldTermios; t.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG | NOFLSH); t.c_iflag &= ~(BRKINT | ICRNL | ISTRIP | IXON); t.c_cflag &= ~(CSIZE | PARENB); t.c_cflag |= CS8; t.c_oflag &= ~(OPOST); t.c_cc[VMIN] = 1; t.c_cc[VTIME] = 0;#if defined(linux) t.c_line = 0;#elif defined(__FreeBSD__) t.c_cc[VDISCARD] = _POSIX_VDISABLE; t.c_cc[VLNEXT] = _POSIX_VDISABLE; t.c_cc[VSTART] = _POSIX_VDISABLE; t.c_cc[VSTOP] = _POSIX_VDISABLE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -