#include #include #include #include #include #include #include #include #include #include "ctl.h" #include "interpreter/interpreter.h" #include "tools/log/log.h" static void goto_col(int x) { char seq[32]; int n = snprintf(seq, sizeof(seq), "\r\033[%dC", x+1); /* 1-based */ write(STDOUT_FILENO, seq, n); } int replace_chars(int start_pos, int old_len, const char *new_str) { // 1. 移动光标到起始位置 if(new_str == NULL) return -1; char move_cmd[16]; int move_len = snprintf(move_cmd, sizeof(move_cmd), "\033[%dG", start_pos + 1); // ANSI 列从1开始 write(STDOUT_FILENO, move_cmd, move_len); // 2. 写入新内容 int new_len = strlen(new_str); write(STDOUT_FILENO, new_str, new_len-1); // 3. 如果新内容比原内容短,删除剩余部分 if (new_len < old_len) { write(STDOUT_FILENO, "\033[K", 3); } } int take_history(Ctl *self,int *currant_index,int *length,char *buf,int toward) { if(toward ==1) { if(*currant_index>0) (*currant_index)--; else *currant_index = HISTORY_BUF-1; } else if(toward == 0) { if(*currant_index history[*currant_index] == NULL){ *length = *length-2; return 0; } replace_chars(sizeof(PROMPT)-1,*length,self->history[*currant_index]); memcpy(buf,self->history[*currant_index],MAX_BUF); buf[strlen(buf)-1] = '\0'; *length = strlen(buf); return 0; } int del_char(int length, int index, char *buf) { int buf_idx = index - sizeof(PROMPT); // 待删字符在 buf 中的下标 if (length == index) // 行尾退格 { write(STDOUT_FILENO, "\b \b", 3); return 1; } int str_len = length - index; char *new_str = (char*)malloc(str_len); memcpy(new_str, &buf[buf_idx+2], str_len-1); write(STDOUT_FILENO, new_str, str_len); goto_col(length - 2); write(STDOUT_FILENO, "\033[K", 3); goto_col(index - 1); char *restr = buf+index-sizeof(PROMPT)+1; memcpy(restr,new_str,str_len); free(new_str); return 1; } int get_cursor(int *col) { int row; struct termios old, tmp; tcgetattr(STDIN_FILENO, &old); tmp = old; cfmakeraw(&tmp); tcsetattr(STDIN_FILENO, TCSADRAIN, &tmp); /* 发 DSR 查询:ESC [ 6 n */ write(STDOUT_FILENO, "\033[6n", 4); /* 读应答,最大 16 字节足够:ESC [ rr ; cc R */ char buf[16] = {0}; int i = 0; while (i < sizeof(buf) - 1) { read(STDIN_FILENO, &buf[i], 1); if (buf[i] == 'R') break; ++i; } buf[++i] = '\0'; tcsetattr(STDIN_FILENO, TCSADRAIN, &old); /* 恢复终端属性 */ /* 解析 ESC [ row ; col R */ if (sscanf(buf, "\033[%d;%dR",&row, col) != 2) return -1; return 0; } int read_line(char *buf,Ctl *self) { int length = 0; char input_buf; int cursor_index = 0; int currant_index = self->index; while(read(0,&input_buf,1)==1&&length= 2 && buf[length - 1] == 0x5B && buf[length - 2] == 0x1B) { switch(input_buf) { case 0x41: take_history(self,&currant_index,&length,buf,1); break; //一定记得加break!!! case 0x42: take_history(self,&currant_index,&length,buf,0); break; case 0x43: get_cursor(&cursor_index); length = length-2; if(cursor_index == sizeof(PROMPT)+length) { break; } write(STDOUT_FILENO, "\x1b[C", 3); break; case 0x44: get_cursor(&cursor_index); length = length -2; if(cursor_index == sizeof(PROMPT)) { break; } write(STDOUT_FILENO, "\x1b[D", 3); break; } break; } default: write(STDOUT_FILENO, &input_buf, 1); buf[length++] = input_buf; cursor_index = length; break; } } if(length>=MAX_BUF) { perror("SYS:input pass edge"); } } int infifo(Ctl *self,const char *cmd) { if(self->history[self->index]!=NULL){ memcpy(self->history[self->index],cmd,MAX_BUF); } else{ self->history[self->index] = (char*)malloc(MAX_BUF*sizeof(char)); memcpy(self->history[self->index],cmd,MAX_BUF); } //存储命令历史s if(self->indexindex++; } else{ self->index = 0; } } int free_history(Ctl *self) { for(int i = 0;i<6;i++) { if(self->history[i]!=NULL) { free(self->history[i]); } } return 1; } int teml(Ctl *self,int fifo[2]) { char input[MAX_BUF] = {'\0'}; ctx *command = (ctx*)malloc(sizeof(ctx)); Cmd cmd_dir[10]; init_interpreter(cmd_dir,command,fifo);//初始化解释器 //创建线程用于定期清理日志 pthread_create(&self->logwathcher,NULL,self->logmanager->clear_log,self->logmanager); command->statue = 0; do { //设置缓冲区,接收用户输入 write(STDOUT_FILENO,PROMPT,sizeof(PROMPT)); command->line = read_line(input,self); if(command->line == -1) perror("sys error"); //将用户输入入队 infifo(self,input); memcpy(command->command,input,sizeof(input)); interpret(SIG_MOD,command,cmd_dir); const char fexp[256] = {'\0'}; memcpy(&input,&fexp,MAX_BUF); }while(command->statue == 0); pthread_kill(self->logwathcher,SIGUSR1); //关闭log定期清理程序 close(fifo[0]); close(fifo[1]); free_history(self); free(command); } Ctl *init_tem(log_manager *logmanager) { //初始化终端对象 Ctl *tem = (Ctl*)malloc(sizeof(Ctl)); tem->run = teml; tem->infifo = infifo; tem->index = 0; tem->logmanager = logmanager; for(int i =0;i<6;i++) { tem->history[i] = NULL; } struct termios tio_setting; tcgetattr(STDIN_FILENO,&tio_setting); tio_setting.c_lflag &= ~(ICANON|ECHO); tio_setting.c_cflag |=ISIG; tio_setting.c_cc[VMIN] =1; tio_setting.c_cc[VTIME] = 0; tcsetattr(STDERR_FILENO,TCSAFLUSH,&tio_setting); return tem; }