console.cpp
来自「最经典的bittorrent协议的实现的源码」· C++ 代码 · 共 1,273 行 · 第 1/3 页
CPP
1,273 行
#include <stdlib.h> // atoi()#include <sys/types.h> // fstat(), FD_SET(), fork()#include <sys/stat.h> // fstat()#include <unistd.h> // isatty(), fork(), setsid()#include <string.h>#include <errno.h>#include <ctype.h> // isdigit()#include <signal.h>#include "btconfig.h"#include "console.h"#include "ctcs.h"#include "btcontent.h"#include "tracker.h"#include "peer.h"#include "peerlist.h"#include "bitfield.h"#include "bttime.h"#include "sigint.h"#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_SNPRINTF)#include "compat.h"#endif// console.cpp: Copyright 2007 Dennis Holmes (dholmes@rahul.net)// input mode definitions#define K_CHARS 0#define K_LINES 1const char LIVE_CHAR[4] = {'-', '\\','|','/'};Console CONSOLE;//===========================================================================// ConStream class functionsConStream::ConStream(){ m_stream = (FILE *)0; m_name = (char *)0; m_newline = 1; m_suspend = 0; m_inputmode = K_LINES;}ConStream::~ConStream(){ if( !m_suspend ) _newline(); if( m_stream ) fclose(m_stream); if( m_name ) delete []m_name;}void ConStream::Close(){ if( m_stream ){ fclose(m_stream); m_stream = (FILE *)0; } m_suspend = 1;}void ConStream::Associate(FILE *stream, const char *name, int mode){ m_stream = stream; m_filemode = mode; if( m_name = new char[strlen(name)+1] ) strcpy(m_name, name); else CONSOLE.Warning(1, "Failed to allocate memory for output filename.");}int ConStream::SameDev(ConStream *master) const{ struct stat sbone, sbtwo; if( master == this || Fileno() == master->Fileno() ) return 1; else if( Fileno() < 0 || master->Fileno() < 0 ) return 0; if( !fstat(Fileno(), &sbone) && !fstat(master->Fileno(), &sbtwo) ) return (sbone.st_dev==sbtwo.st_dev && sbone.st_ino==sbtwo.st_ino) ? 1 : 0; else return 0;}int ConStream::IsTTY() const{ return (Fileno() >= 0) ? isatty(Fileno()) : 0;}void ConStream::PreserveMode(){ if( !IsTTY() ) return;#if defined(USE_TERMIOS) tcgetattr(Fileno(), &m_original);#elif defined(USE_TERMIO) ioctl(Fileno(), TCGETA, &m_original);#elif defined(USE_SGTTY) gtty(Fileno(), &m_original);#endif}void ConStream::RestoreMode(){ if( !IsTTY() ) return;#if defined(USE_TERMIOS) tcsetattr(Fileno(), TCSANOW, &m_original);#elif defined(USE_TERMIO) ioctl(Fileno(), TCSETA, &m_original);#elif defined(USE_SGTTY) stty(Fileno(), &m_original);#endif}void ConStream::SetInputMode(int keymode){ if( m_suspend || !IsTTY() ) return;#if defined(USE_TERMIOS) struct termios termset; tcgetattr(Fileno(), &termset);#elif defined(USE_TERMIO) struct termio termset; ioctl(Fileno(), TCGETA, &termset);#elif defined(USE_SGTTY) struct sgttyb termset; gtty(Fileno(), &termset);#endif switch(keymode) { case K_CHARS: // read a char at a time, no echo#if defined(USE_TERMIOS) termset.c_lflag &= ~(ICANON | ECHO); tcsetattr(Fileno(), TCSANOW, &termset);#elif defined(USE_TERMIO) termset.c_lflag &= ~(ICANON | ECHO); ioctl(Fileno(), TCSETA, &termset);#elif defined(USE_SGTTY) termset.sg_flags |= CBREAK; termset.sg_flags &= ~ECHO; stty(Fileno(), &termset);#endif break; case K_LINES: // read a line at a time (allow terminal editing)#if defined(USE_TERMIOS) termset.c_lflag |= (ICANON | ECHO); tcsetattr(Fileno(), TCSANOW, &termset);#elif defined(USE_TERMIO) termset.c_lflag |= (ICANON | ECHO); ioctl(Fileno(), TCSETA, &termset);#elif defined(USE_SGTTY) termset.sg_flags &= ~CBREAK; termset.sg_flags |= ECHO; stty(Fileno(), &termset);#endif break; default: break; } m_inputmode = keymode;}int ConStream::Output(const char *message, va_list ap){ if( m_suspend ) return 0; int old_newline = m_newline; _newline(); _convprintf(message, ap); _newline(); fflush(m_stream); return (old_newline==m_newline) ? 0 : 1;}int ConStream::Output_n(const char *message, va_list ap){ if( m_suspend ) return 0; int old_newline = m_newline; if( !*message ) _newline(); else _convprintf(message, ap); fflush(m_stream); return (old_newline==m_newline) ? 0 : 1;}int ConStream::Update(const char *message, va_list ap){ if( m_suspend ) return 0; int old_newline = m_newline; if( !m_newline) fprintf(m_stream, IsTTY() ? "\r" : "\n"); _convprintf(message, ap); fflush(m_stream); return (old_newline==m_newline) ? 0 : 1;}char *ConStream::Input(char *field, size_t length){ if( m_suspend ) return (char *)0; m_newline = 1; return fgets(field, length, m_stream);}int ConStream::CharIn(){ if( m_suspend ) return 0; return fgetc(m_stream);}inline void ConStream::_newline(){ if( !m_newline ){ fprintf(m_stream, "\n"); m_newline = 1; }}inline int ConStream::_convprintf(const char *format, va_list ap){ int r = ( '\n' == format[strlen(format)-1] ); m_newline = r; return vfprintf(m_stream, format, ap);}//===========================================================================// Console class functionsConsole::Console(){ m_skip_status = m_status_last = 0; m_live_idx = 0; m_oldfd = -1; m_status_format = 0; int i = 0; m_statusline[i++] = &Console::StatusLine0; m_statusline[i++] = &Console::StatusLine1; if( STATUSLINES > i ){ fprintf(stderr, "Unassigned status line in Console() constructor!\n"); exit(1); }else if ( STATUSLINES < i ){ fprintf(stderr, "Value of STATUSLINES is too small!\n"); exit(1); } m_stdout.Associate(stdout, "stdout", 1); m_stderr.Associate(stderr, "stderr", 1); m_stdin.Associate(stdin, "stdin", 0); m_off.Associate(NULL, "off", 1); m_off.Suspend(); m_streams[O_NORMAL] = &m_stdout; m_streams[O_WARNING] = &m_stderr; m_streams[O_DEBUG] = &m_stderr; m_streams[O_INTERACT] = &m_stdout; m_streams[O_INPUT] = &m_stdin; m_streams[O_INPUT]->PreserveMode(); m_streams[O_INPUT]->SetInputMode(K_CHARS); m_conmode = K_CHARS;}Console::~Console(){ m_streams[O_INPUT]->RestoreMode();}int Console::IntervalCheck(fd_set *rfdp, fd_set *wfdp){ Status(0); if( m_oldfd >= 0 ){ FD_CLR(m_oldfd, rfdp); m_oldfd = -1; } if( !m_streams[O_INPUT]->IsSuspended() ){ FD_SET(m_streams[O_INPUT]->Fileno(), rfdp); return m_streams[O_INPUT]->Fileno(); }else{ if( m_streams[O_INPUT]->Fileno() >= 0 ) FD_CLR(m_streams[O_INPUT]->Fileno(), rfdp); return 0; }}void Console::User(fd_set *rfdp, fd_set *wfdp, int *nready, fd_set *rfdnextp, fd_set *wfdnextp){ static char pending = '\0'; static int inc, count; char c, param[MAXPATHLEN], *s; if( m_streams[O_INPUT]->Fileno() >= 0 && FD_ISSET(m_streams[O_INPUT]->Fileno(), rfdp) ){ FD_CLR(m_streams[O_INPUT]->Fileno(), rfdnextp); (*nready)--; if( K_LINES==m_streams[O_INPUT]->GetInputMode() ){ // command parameter SyncNewlines(O_INPUT); if( m_streams[O_INPUT]->Input(param, sizeof(param)) ){ if( s = strchr(param, '\n') ) *s = '\0'; if( '0'==pending ){ if( OperatorMenu(param) ) pending = '\0'; }else{ m_streams[O_INPUT]->SetInputMode(K_CHARS); if( *param ) switch( pending ){ case 'n': // get1file if( arg_file_to_download ) delete []arg_file_to_download; arg_file_to_download = new char[strlen(param) + 1]; if( !arg_file_to_download ) CONSOLE.Warning(1, "error, failed to allocate memory for option"); else strcpy(arg_file_to_download, param); BTCONTENT.SetFilter(); break; case 'S': // CTCS server if( !strchr(param, ':') ) Interact("Invalid input"); else{ if( arg_ctcs ) delete []arg_ctcs; arg_ctcs = new char[strlen(param) + 1]; if( !arg_ctcs ) CONSOLE.Warning(1, "error, failed to allocate memory for option"); else{ strcpy(arg_ctcs, param); CTCS.Initial(); CTCS.Reset(1); } } break; case 'X': // completion command (user exit) if( arg_completion_exit ) delete []arg_completion_exit; arg_completion_exit = new char[strlen(param) + 1]; if( !arg_completion_exit ) CONSOLE.Warning(1, "error, failed to allocate memory for option"); else strcpy(arg_completion_exit, param); break; case 'Q': // quit if( 'y'==*param || 'Y'==*param ){ Tracker.ClearRestart(); Tracker.SetStoped(); } break; default: Interact("Input mode error"); } } }else{ if( m_streams[O_INPUT]->Eof() ){ Interact("End of input reached."); if( ChangeChannel(O_INPUT, "off") < 0 ) m_streams[O_INPUT]->Suspend(); }else if(errno){ if( ENODEV==errno || ENOTTY==errno ) m_streams[O_INPUT]->Suspend(); else Interact("Input error: %s", strerror(errno)); }else Interact("Input error!"); } if( '0' != pending ){ m_streams[O_INPUT]->SetInputMode(K_CHARS); Status(1); } }else{ // command character received m_skip_status = 1; c = m_streams[O_INPUT]->CharIn(); if( c!='+' && c!='-' ) pending = c; switch( c ){ case 'h': // help case '?': // help Interact("Available commands:"); Interact(" %-9s%-30s %-9s%s", "[Esc/0]", "Operator menu", "m[+/-]", "Adjust min peers count"); Interact(" %-9s%-30s %-9s%s", "d[+/-]", "Adjust download limit", "M[+/-]", "Adjust max peers count"); Interact(" %-9s%-30s %-9s%s", "u[+/-]", "Adjust upload limit", "C[+/-]", "Adjust max cache size"); Interact(" %-9s%-30s %-9s%s", "n", "Download specific files", "S", "Set/change CTCS server"); Interact(" %-9s%-30s %-9s%s", "e[+/-]", "Adjust seed exit time", "v", "Toggle verbose mode"); Interact(" %-9s%-30s %-9s%s", "E[+/-]", "Adjust seed exit ratio", "Q", "Quit"); Interact(" %-9s%-30s %-9s%s", "X", "Completion command", "", ""); break; case 'd': // download bw limit case 'u': // upload bw limit case 'e': // seed time case 'E': // seed ratio case 'm': // min peers case 'M': // max peers case 'C': // max cache size inc = 1; count = 0; Interact_n(""); break; case 'n': // get1file m_streams[O_INPUT]->SetInputMode(K_LINES); ShowFiles();
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?